Additional JWT Security Token Support
[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
72 #define BRANCH_COST 10
73 #define INLINE_LENGTH_LIMIT 20
74
75 /* These have 'cfg' as an implicit argument */
76 #define INLINE_FAILURE(msg) do {                                                                        \
77         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
78                 inline_failure (cfg, msg);                                                                              \
79                 goto exception_exit;                                                                                    \
80         } \
81         } while (0)
82 #define CHECK_CFG_EXCEPTION do {\
83                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
84                         goto exception_exit;                                            \
85         } while (0)
86 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
87                 method_access_failure ((cfg), (method), (cmethod));                     \
88                 goto exception_exit;                                                                            \
89         } while (0)
90 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
91                 field_access_failure ((cfg), (method), (field));                        \
92                 goto exception_exit;    \
93         } while (0)
94 #define GENERIC_SHARING_FAILURE(opcode) do {            \
95                 if (cfg->gshared) {                                                                     \
96                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
97                         goto exception_exit;    \
98                 }                       \
99         } while (0)
100 #define GSHAREDVT_FAILURE(opcode) do {          \
101         if (cfg->gsharedvt) {                                                                                           \
102                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
103                 goto exception_exit;                                                                                    \
104         }                                                                                                                                       \
105         } while (0)
106 #define OUT_OF_MEMORY_FAILURE do {      \
107                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
108                 goto exception_exit;    \
109         } while (0)
110 #define DISABLE_AOT(cfg) do { \
111                 if ((cfg)->verbose_level >= 2)                                            \
112                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
113                 (cfg)->disable_aot = TRUE;                                                        \
114         } while (0)
115 #define LOAD_ERROR do { \
116                 break_on_unverified ();                                                         \
117                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
118                 goto exception_exit;                                                                    \
119         } while (0)
120
121 #define TYPE_LOAD_ERROR(klass) do { \
122                 cfg->exception_ptr = klass; \
123                 LOAD_ERROR;                                     \
124         } while (0)
125
126 /* Determine whenever 'ins' represents a load of the 'this' argument */
127 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
128
129 static int ldind_to_load_membase (int opcode);
130 static int stind_to_store_membase (int opcode);
131
132 int mono_op_to_op_imm (int opcode);
133 int mono_op_to_op_imm_noemul (int opcode);
134
135 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
136
137 /* helper methods signatures */
138 static MonoMethodSignature *helper_sig_class_init_trampoline;
139 static MonoMethodSignature *helper_sig_domain_get;
140 static MonoMethodSignature *helper_sig_generic_class_init_trampoline;
141 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
142 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
143 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
144 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
145
146 /*
147  * Instruction metadata
148  */
149 #ifdef MINI_OP
150 #undef MINI_OP
151 #endif
152 #ifdef MINI_OP3
153 #undef MINI_OP3
154 #endif
155 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
156 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
157 #define NONE ' '
158 #define IREG 'i'
159 #define FREG 'f'
160 #define VREG 'v'
161 #define XREG 'x'
162 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
163 #define LREG IREG
164 #else
165 #define LREG 'l'
166 #endif
167 /* keep in sync with the enum in mini.h */
168 const char
169 ins_info[] = {
170 #include "mini-ops.h"
171 };
172 #undef MINI_OP
173 #undef MINI_OP3
174
175 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
176 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
177 /* 
178  * This should contain the index of the last sreg + 1. This is not the same
179  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
180  */
181 const gint8 ins_sreg_counts[] = {
182 #include "mini-ops.h"
183 };
184 #undef MINI_OP
185 #undef MINI_OP3
186
187 #define MONO_INIT_VARINFO(vi,id) do { \
188         (vi)->range.first_use.pos.bid = 0xffff; \
189         (vi)->reg = -1; \
190         (vi)->idx = (id); \
191 } while (0)
192
193 void
194 mono_inst_set_src_registers (MonoInst *ins, int *regs)
195 {
196         ins->sreg1 = regs [0];
197         ins->sreg2 = regs [1];
198         ins->sreg3 = regs [2];
199 }
200
201 guint32
202 mono_alloc_ireg (MonoCompile *cfg)
203 {
204         return alloc_ireg (cfg);
205 }
206
207 guint32
208 mono_alloc_lreg (MonoCompile *cfg)
209 {
210         return alloc_lreg (cfg);
211 }
212
213 guint32
214 mono_alloc_freg (MonoCompile *cfg)
215 {
216         return alloc_freg (cfg);
217 }
218
219 guint32
220 mono_alloc_preg (MonoCompile *cfg)
221 {
222         return alloc_preg (cfg);
223 }
224
225 guint32
226 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
227 {
228         return alloc_dreg (cfg, stack_type);
229 }
230
231 /*
232  * mono_alloc_ireg_ref:
233  *
234  *   Allocate an IREG, and mark it as holding a GC ref.
235  */
236 guint32
237 mono_alloc_ireg_ref (MonoCompile *cfg)
238 {
239         return alloc_ireg_ref (cfg);
240 }
241
242 /*
243  * mono_alloc_ireg_mp:
244  *
245  *   Allocate an IREG, and mark it as holding a managed pointer.
246  */
247 guint32
248 mono_alloc_ireg_mp (MonoCompile *cfg)
249 {
250         return alloc_ireg_mp (cfg);
251 }
252
253 /*
254  * mono_alloc_ireg_copy:
255  *
256  *   Allocate an IREG with the same GC type as VREG.
257  */
258 guint32
259 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
260 {
261         if (vreg_is_ref (cfg, vreg))
262                 return alloc_ireg_ref (cfg);
263         else if (vreg_is_mp (cfg, vreg))
264                 return alloc_ireg_mp (cfg);
265         else
266                 return alloc_ireg (cfg);
267 }
268
269 guint
270 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
271 {
272         if (type->byref)
273                 return OP_MOVE;
274
275         type = mini_replace_type (type);
276 handle_enum:
277         switch (type->type) {
278         case MONO_TYPE_I1:
279         case MONO_TYPE_U1:
280         case MONO_TYPE_BOOLEAN:
281                 return OP_MOVE;
282         case MONO_TYPE_I2:
283         case MONO_TYPE_U2:
284         case MONO_TYPE_CHAR:
285                 return OP_MOVE;
286         case MONO_TYPE_I4:
287         case MONO_TYPE_U4:
288                 return OP_MOVE;
289         case MONO_TYPE_I:
290         case MONO_TYPE_U:
291         case MONO_TYPE_PTR:
292         case MONO_TYPE_FNPTR:
293                 return OP_MOVE;
294         case MONO_TYPE_CLASS:
295         case MONO_TYPE_STRING:
296         case MONO_TYPE_OBJECT:
297         case MONO_TYPE_SZARRAY:
298         case MONO_TYPE_ARRAY:    
299                 return OP_MOVE;
300         case MONO_TYPE_I8:
301         case MONO_TYPE_U8:
302 #if SIZEOF_REGISTER == 8
303                 return OP_MOVE;
304 #else
305                 return OP_LMOVE;
306 #endif
307         case MONO_TYPE_R4:
308                 return OP_FMOVE;
309         case MONO_TYPE_R8:
310                 return OP_FMOVE;
311         case MONO_TYPE_VALUETYPE:
312                 if (type->data.klass->enumtype) {
313                         type = mono_class_enum_basetype (type->data.klass);
314                         goto handle_enum;
315                 }
316                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
317                         return OP_XMOVE;
318                 return OP_VMOVE;
319         case MONO_TYPE_TYPEDBYREF:
320                 return OP_VMOVE;
321         case MONO_TYPE_GENERICINST:
322                 type = &type->data.generic_class->container_class->byval_arg;
323                 goto handle_enum;
324         case MONO_TYPE_VAR:
325         case MONO_TYPE_MVAR:
326                 g_assert (cfg->generic_sharing_context);
327                 if (mini_type_var_is_vt (cfg, type))
328                         return OP_VMOVE;
329                 else
330                         return OP_MOVE;
331         default:
332                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
333         }
334         return -1;
335 }
336
337 void
338 mono_print_bb (MonoBasicBlock *bb, const char *msg)
339 {
340         int i;
341         MonoInst *tree;
342
343         printf ("\n%s %d: [IN: ", msg, bb->block_num);
344         for (i = 0; i < bb->in_count; ++i)
345                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
346         printf (", OUT: ");
347         for (i = 0; i < bb->out_count; ++i)
348                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
349         printf (" ]\n");
350         for (tree = bb->code; tree; tree = tree->next)
351                 mono_print_ins_index (-1, tree);
352 }
353
354 void
355 mono_create_helper_signatures (void)
356 {
357         helper_sig_domain_get = mono_create_icall_signature ("ptr");
358         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
359         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
360         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
361         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
362         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
363         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
364 }
365
366 static MONO_NEVER_INLINE void
367 break_on_unverified (void)
368 {
369         if (mini_get_debug_options ()->break_on_unverified)
370                 G_BREAKPOINT ();
371 }
372
373 static MONO_NEVER_INLINE void
374 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
375 {
376         char *method_fname = mono_method_full_name (method, TRUE);
377         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
378         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
379         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
380         g_free (method_fname);
381         g_free (cil_method_fname);
382 }
383
384 static MONO_NEVER_INLINE void
385 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
386 {
387         char *method_fname = mono_method_full_name (method, TRUE);
388         char *field_fname = mono_field_full_name (field);
389         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
390         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
391         g_free (method_fname);
392         g_free (field_fname);
393 }
394
395 static MONO_NEVER_INLINE void
396 inline_failure (MonoCompile *cfg, const char *msg)
397 {
398         if (cfg->verbose_level >= 2)
399                 printf ("inline failed: %s\n", msg);
400         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
401 }
402
403 static MONO_NEVER_INLINE void
404 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
405 {
406         if (cfg->verbose_level > 2)                                                                                     \
407                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), __LINE__);
408         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
409 }
410
411 static MONO_NEVER_INLINE void
412 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
413 {
414         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
415         if (cfg->verbose_level >= 2)
416                 printf ("%s\n", cfg->exception_message);
417         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
418 }
419
420 /*
421  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
422  * foo<T> (int i) { ldarg.0; box T; }
423  */
424 #define UNVERIFIED do { \
425         if (cfg->gsharedvt) { \
426                 if (cfg->verbose_level > 2)                                                                     \
427                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
428                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
429                 goto exception_exit;                                                                                    \
430         }                                                                                                                                       \
431         break_on_unverified ();                                                                                         \
432         goto unverified;                                                                                                        \
433 } while (0)
434
435 #define GET_BBLOCK(cfg,tblock,ip) do {  \
436                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
437                 if (!(tblock)) {        \
438                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
439             NEW_BBLOCK (cfg, (tblock)); \
440                         (tblock)->cil_code = (ip);      \
441                         ADD_BBLOCK (cfg, (tblock));     \
442                 } \
443         } while (0)
444
445 #if defined(TARGET_X86) || defined(TARGET_AMD64)
446 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
447                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
448                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
449                 (dest)->sreg1 = (sr1); \
450                 (dest)->sreg2 = (sr2); \
451                 (dest)->inst_imm = (imm); \
452                 (dest)->backend.shift_amount = (shift); \
453                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
454         } while (0)
455 #endif
456
457 #if SIZEOF_REGISTER == 8
458 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
459                 /* FIXME: Need to add many more cases */ \
460                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
461                         MonoInst *widen; \
462                         int dr = alloc_preg (cfg); \
463                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
464                         (ins)->sreg2 = widen->dreg; \
465                 } \
466         } while (0)
467 #else
468 #define ADD_WIDEN_OP(ins, arg1, arg2)
469 #endif
470
471 #define ADD_BINOP(op) do {      \
472                 MONO_INST_NEW (cfg, ins, (op)); \
473                 sp -= 2;        \
474                 ins->sreg1 = sp [0]->dreg;      \
475                 ins->sreg2 = sp [1]->dreg;      \
476                 type_from_op (ins, sp [0], sp [1]);     \
477                 CHECK_TYPE (ins);       \
478                 /* Have to insert a widening op */               \
479         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
480         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
481         MONO_ADD_INS ((cfg)->cbb, (ins)); \
482         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
483         } while (0)
484
485 #define ADD_UNOP(op) do {       \
486                 MONO_INST_NEW (cfg, ins, (op)); \
487                 sp--;   \
488                 ins->sreg1 = sp [0]->dreg;      \
489                 type_from_op (ins, sp [0], NULL);       \
490                 CHECK_TYPE (ins);       \
491         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
492         MONO_ADD_INS ((cfg)->cbb, (ins)); \
493                 *sp++ = mono_decompose_opcode (cfg, ins); \
494         } while (0)
495
496 #define ADD_BINCOND(next_block) do {    \
497                 MonoInst *cmp;  \
498                 sp -= 2; \
499                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
500                 cmp->sreg1 = sp [0]->dreg;      \
501                 cmp->sreg2 = sp [1]->dreg;      \
502                 type_from_op (cmp, sp [0], sp [1]);     \
503                 CHECK_TYPE (cmp);       \
504                 type_from_op (ins, sp [0], sp [1]);     \
505                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
506                 GET_BBLOCK (cfg, tblock, target);               \
507                 link_bblock (cfg, bblock, tblock);      \
508                 ins->inst_true_bb = tblock;     \
509                 if ((next_block)) {     \
510                         link_bblock (cfg, bblock, (next_block));        \
511                         ins->inst_false_bb = (next_block);      \
512                         start_new_bblock = 1;   \
513                 } else {        \
514                         GET_BBLOCK (cfg, tblock, ip);           \
515                         link_bblock (cfg, bblock, tblock);      \
516                         ins->inst_false_bb = tblock;    \
517                         start_new_bblock = 2;   \
518                 }       \
519                 if (sp != stack_start) {                                                                        \
520                     handle_stack_args (cfg, stack_start, sp - stack_start); \
521                         CHECK_UNVERIFIABLE (cfg); \
522                 } \
523         MONO_ADD_INS (bblock, cmp); \
524                 MONO_ADD_INS (bblock, ins);     \
525         } while (0)
526
527 /* *
528  * link_bblock: Links two basic blocks
529  *
530  * links two basic blocks in the control flow graph, the 'from'
531  * argument is the starting block and the 'to' argument is the block
532  * the control flow ends to after 'from'.
533  */
534 static void
535 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
536 {
537         MonoBasicBlock **newa;
538         int i, found;
539
540 #if 0
541         if (from->cil_code) {
542                 if (to->cil_code)
543                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
544                 else
545                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
546         } else {
547                 if (to->cil_code)
548                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
549                 else
550                         printf ("edge from entry to exit\n");
551         }
552 #endif
553
554         found = FALSE;
555         for (i = 0; i < from->out_count; ++i) {
556                 if (to == from->out_bb [i]) {
557                         found = TRUE;
558                         break;
559                 }
560         }
561         if (!found) {
562                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
563                 for (i = 0; i < from->out_count; ++i) {
564                         newa [i] = from->out_bb [i];
565                 }
566                 newa [i] = to;
567                 from->out_count++;
568                 from->out_bb = newa;
569         }
570
571         found = FALSE;
572         for (i = 0; i < to->in_count; ++i) {
573                 if (from == to->in_bb [i]) {
574                         found = TRUE;
575                         break;
576                 }
577         }
578         if (!found) {
579                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
580                 for (i = 0; i < to->in_count; ++i) {
581                         newa [i] = to->in_bb [i];
582                 }
583                 newa [i] = from;
584                 to->in_count++;
585                 to->in_bb = newa;
586         }
587 }
588
589 void
590 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
591 {
592         link_bblock (cfg, from, to);
593 }
594
595 /**
596  * mono_find_block_region:
597  *
598  *   We mark each basic block with a region ID. We use that to avoid BB
599  *   optimizations when blocks are in different regions.
600  *
601  * Returns:
602  *   A region token that encodes where this region is, and information
603  *   about the clause owner for this block.
604  *
605  *   The region encodes the try/catch/filter clause that owns this block
606  *   as well as the type.  -1 is a special value that represents a block
607  *   that is in none of try/catch/filter.
608  */
609 static int
610 mono_find_block_region (MonoCompile *cfg, int offset)
611 {
612         MonoMethodHeader *header = cfg->header;
613         MonoExceptionClause *clause;
614         int i;
615
616         for (i = 0; i < header->num_clauses; ++i) {
617                 clause = &header->clauses [i];
618                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
619                     (offset < (clause->handler_offset)))
620                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
621                            
622                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
623                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
624                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
625                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
626                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
627                         else
628                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
629                 }
630
631                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
632                         return ((i + 1) << 8) | clause->flags;
633         }
634
635         return -1;
636 }
637
638 static GList*
639 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
640 {
641         MonoMethodHeader *header = cfg->header;
642         MonoExceptionClause *clause;
643         int i;
644         GList *res = NULL;
645
646         for (i = 0; i < header->num_clauses; ++i) {
647                 clause = &header->clauses [i];
648                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
649                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
650                         if (clause->flags == type)
651                                 res = g_list_append (res, clause);
652                 }
653         }
654         return res;
655 }
656
657 static void
658 mono_create_spvar_for_region (MonoCompile *cfg, int region)
659 {
660         MonoInst *var;
661
662         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
663         if (var)
664                 return;
665
666         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
667         /* prevent it from being register allocated */
668         var->flags |= MONO_INST_VOLATILE;
669
670         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
671 }
672
673 MonoInst *
674 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
675 {
676         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
677 }
678
679 static MonoInst*
680 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
681 {
682         MonoInst *var;
683
684         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
685         if (var)
686                 return var;
687
688         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
689         /* prevent it from being register allocated */
690         var->flags |= MONO_INST_VOLATILE;
691
692         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
693
694         return var;
695 }
696
697 /*
698  * Returns the type used in the eval stack when @type is loaded.
699  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
700  */
701 void
702 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
703 {
704         MonoClass *klass;
705
706         type = mini_replace_type (type);
707         inst->klass = klass = mono_class_from_mono_type (type);
708         if (type->byref) {
709                 inst->type = STACK_MP;
710                 return;
711         }
712
713 handle_enum:
714         switch (type->type) {
715         case MONO_TYPE_VOID:
716                 inst->type = STACK_INV;
717                 return;
718         case MONO_TYPE_I1:
719         case MONO_TYPE_U1:
720         case MONO_TYPE_BOOLEAN:
721         case MONO_TYPE_I2:
722         case MONO_TYPE_U2:
723         case MONO_TYPE_CHAR:
724         case MONO_TYPE_I4:
725         case MONO_TYPE_U4:
726                 inst->type = STACK_I4;
727                 return;
728         case MONO_TYPE_I:
729         case MONO_TYPE_U:
730         case MONO_TYPE_PTR:
731         case MONO_TYPE_FNPTR:
732                 inst->type = STACK_PTR;
733                 return;
734         case MONO_TYPE_CLASS:
735         case MONO_TYPE_STRING:
736         case MONO_TYPE_OBJECT:
737         case MONO_TYPE_SZARRAY:
738         case MONO_TYPE_ARRAY:    
739                 inst->type = STACK_OBJ;
740                 return;
741         case MONO_TYPE_I8:
742         case MONO_TYPE_U8:
743                 inst->type = STACK_I8;
744                 return;
745         case MONO_TYPE_R4:
746         case MONO_TYPE_R8:
747                 inst->type = STACK_R8;
748                 return;
749         case MONO_TYPE_VALUETYPE:
750                 if (type->data.klass->enumtype) {
751                         type = mono_class_enum_basetype (type->data.klass);
752                         goto handle_enum;
753                 } else {
754                         inst->klass = klass;
755                         inst->type = STACK_VTYPE;
756                         return;
757                 }
758         case MONO_TYPE_TYPEDBYREF:
759                 inst->klass = mono_defaults.typed_reference_class;
760                 inst->type = STACK_VTYPE;
761                 return;
762         case MONO_TYPE_GENERICINST:
763                 type = &type->data.generic_class->container_class->byval_arg;
764                 goto handle_enum;
765         case MONO_TYPE_VAR:
766         case MONO_TYPE_MVAR:
767                 g_assert (cfg->generic_sharing_context);
768                 if (mini_is_gsharedvt_type (cfg, type)) {
769                         g_assert (cfg->gsharedvt);
770                         inst->type = STACK_VTYPE;
771                 } else {
772                         inst->type = STACK_OBJ;
773                 }
774                 return;
775         default:
776                 g_error ("unknown type 0x%02x in eval stack type", type->type);
777         }
778 }
779
780 /*
781  * The following tables are used to quickly validate the IL code in type_from_op ().
782  */
783 static const char
784 bin_num_table [STACK_MAX] [STACK_MAX] = {
785         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
786         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
787         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
788         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
789         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
790         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
791         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
792         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
793 };
794
795 static const char 
796 neg_table [] = {
797         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
798 };
799
800 /* reduce the size of this table */
801 static const char
802 bin_int_table [STACK_MAX] [STACK_MAX] = {
803         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
804         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
805         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
806         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
807         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
808         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
809         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
810         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
811 };
812
813 static const char
814 bin_comp_table [STACK_MAX] [STACK_MAX] = {
815 /*      Inv i  L  p  F  &  O  vt */
816         {0},
817         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
818         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
819         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
820         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
821         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
822         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
823         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
824 };
825
826 /* reduce the size of this table */
827 static const char
828 shift_table [STACK_MAX] [STACK_MAX] = {
829         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
830         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
836         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
837 };
838
839 /*
840  * Tables to map from the non-specific opcode to the matching
841  * type-specific opcode.
842  */
843 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
844 static const guint16
845 binops_op_map [STACK_MAX] = {
846         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
847 };
848
849 /* handles from CEE_NEG to CEE_CONV_U8 */
850 static const guint16
851 unops_op_map [STACK_MAX] = {
852         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
853 };
854
855 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
856 static const guint16
857 ovfops_op_map [STACK_MAX] = {
858         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
859 };
860
861 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
862 static const guint16
863 ovf2ops_op_map [STACK_MAX] = {
864         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
865 };
866
867 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
868 static const guint16
869 ovf3ops_op_map [STACK_MAX] = {
870         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
871 };
872
873 /* handles from CEE_BEQ to CEE_BLT_UN */
874 static const guint16
875 beqops_op_map [STACK_MAX] = {
876         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
877 };
878
879 /* handles from CEE_CEQ to CEE_CLT_UN */
880 static const guint16
881 ceqops_op_map [STACK_MAX] = {
882         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
883 };
884
885 /*
886  * Sets ins->type (the type on the eval stack) according to the
887  * type of the opcode and the arguments to it.
888  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
889  *
890  * FIXME: this function sets ins->type unconditionally in some cases, but
891  * it should set it to invalid for some types (a conv.x on an object)
892  */
893 static void
894 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
895
896         switch (ins->opcode) {
897         /* binops */
898         case CEE_ADD:
899         case CEE_SUB:
900         case CEE_MUL:
901         case CEE_DIV:
902         case CEE_REM:
903                 /* FIXME: check unverifiable args for STACK_MP */
904                 ins->type = bin_num_table [src1->type] [src2->type];
905                 ins->opcode += binops_op_map [ins->type];
906                 break;
907         case CEE_DIV_UN:
908         case CEE_REM_UN:
909         case CEE_AND:
910         case CEE_OR:
911         case CEE_XOR:
912                 ins->type = bin_int_table [src1->type] [src2->type];
913                 ins->opcode += binops_op_map [ins->type];
914                 break;
915         case CEE_SHL:
916         case CEE_SHR:
917         case CEE_SHR_UN:
918                 ins->type = shift_table [src1->type] [src2->type];
919                 ins->opcode += binops_op_map [ins->type];
920                 break;
921         case OP_COMPARE:
922         case OP_LCOMPARE:
923         case OP_ICOMPARE:
924                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
925                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
926                         ins->opcode = OP_LCOMPARE;
927                 else if (src1->type == STACK_R8)
928                         ins->opcode = OP_FCOMPARE;
929                 else
930                         ins->opcode = OP_ICOMPARE;
931                 break;
932         case OP_ICOMPARE_IMM:
933                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
934                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
935                         ins->opcode = OP_LCOMPARE_IMM;          
936                 break;
937         case CEE_BEQ:
938         case CEE_BGE:
939         case CEE_BGT:
940         case CEE_BLE:
941         case CEE_BLT:
942         case CEE_BNE_UN:
943         case CEE_BGE_UN:
944         case CEE_BGT_UN:
945         case CEE_BLE_UN:
946         case CEE_BLT_UN:
947                 ins->opcode += beqops_op_map [src1->type];
948                 break;
949         case OP_CEQ:
950                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
951                 ins->opcode += ceqops_op_map [src1->type];
952                 break;
953         case OP_CGT:
954         case OP_CGT_UN:
955         case OP_CLT:
956         case OP_CLT_UN:
957                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
958                 ins->opcode += ceqops_op_map [src1->type];
959                 break;
960         /* unops */
961         case CEE_NEG:
962                 ins->type = neg_table [src1->type];
963                 ins->opcode += unops_op_map [ins->type];
964                 break;
965         case CEE_NOT:
966                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
967                         ins->type = src1->type;
968                 else
969                         ins->type = STACK_INV;
970                 ins->opcode += unops_op_map [ins->type];
971                 break;
972         case CEE_CONV_I1:
973         case CEE_CONV_I2:
974         case CEE_CONV_I4:
975         case CEE_CONV_U4:
976                 ins->type = STACK_I4;
977                 ins->opcode += unops_op_map [src1->type];
978                 break;
979         case CEE_CONV_R_UN:
980                 ins->type = STACK_R8;
981                 switch (src1->type) {
982                 case STACK_I4:
983                 case STACK_PTR:
984                         ins->opcode = OP_ICONV_TO_R_UN;
985                         break;
986                 case STACK_I8:
987                         ins->opcode = OP_LCONV_TO_R_UN; 
988                         break;
989                 }
990                 break;
991         case CEE_CONV_OVF_I1:
992         case CEE_CONV_OVF_U1:
993         case CEE_CONV_OVF_I2:
994         case CEE_CONV_OVF_U2:
995         case CEE_CONV_OVF_I4:
996         case CEE_CONV_OVF_U4:
997                 ins->type = STACK_I4;
998                 ins->opcode += ovf3ops_op_map [src1->type];
999                 break;
1000         case CEE_CONV_OVF_I_UN:
1001         case CEE_CONV_OVF_U_UN:
1002                 ins->type = STACK_PTR;
1003                 ins->opcode += ovf2ops_op_map [src1->type];
1004                 break;
1005         case CEE_CONV_OVF_I1_UN:
1006         case CEE_CONV_OVF_I2_UN:
1007         case CEE_CONV_OVF_I4_UN:
1008         case CEE_CONV_OVF_U1_UN:
1009         case CEE_CONV_OVF_U2_UN:
1010         case CEE_CONV_OVF_U4_UN:
1011                 ins->type = STACK_I4;
1012                 ins->opcode += ovf2ops_op_map [src1->type];
1013                 break;
1014         case CEE_CONV_U:
1015                 ins->type = STACK_PTR;
1016                 switch (src1->type) {
1017                 case STACK_I4:
1018                         ins->opcode = OP_ICONV_TO_U;
1019                         break;
1020                 case STACK_PTR:
1021                 case STACK_MP:
1022 #if SIZEOF_VOID_P == 8
1023                         ins->opcode = OP_LCONV_TO_U;
1024 #else
1025                         ins->opcode = OP_MOVE;
1026 #endif
1027                         break;
1028                 case STACK_I8:
1029                         ins->opcode = OP_LCONV_TO_U;
1030                         break;
1031                 case STACK_R8:
1032                         ins->opcode = OP_FCONV_TO_U;
1033                         break;
1034                 }
1035                 break;
1036         case CEE_CONV_I8:
1037         case CEE_CONV_U8:
1038                 ins->type = STACK_I8;
1039                 ins->opcode += unops_op_map [src1->type];
1040                 break;
1041         case CEE_CONV_OVF_I8:
1042         case CEE_CONV_OVF_U8:
1043                 ins->type = STACK_I8;
1044                 ins->opcode += ovf3ops_op_map [src1->type];
1045                 break;
1046         case CEE_CONV_OVF_U8_UN:
1047         case CEE_CONV_OVF_I8_UN:
1048                 ins->type = STACK_I8;
1049                 ins->opcode += ovf2ops_op_map [src1->type];
1050                 break;
1051         case CEE_CONV_R4:
1052         case CEE_CONV_R8:
1053                 ins->type = STACK_R8;
1054                 ins->opcode += unops_op_map [src1->type];
1055                 break;
1056         case OP_CKFINITE:
1057                 ins->type = STACK_R8;           
1058                 break;
1059         case CEE_CONV_U2:
1060         case CEE_CONV_U1:
1061                 ins->type = STACK_I4;
1062                 ins->opcode += ovfops_op_map [src1->type];
1063                 break;
1064         case CEE_CONV_I:
1065         case CEE_CONV_OVF_I:
1066         case CEE_CONV_OVF_U:
1067                 ins->type = STACK_PTR;
1068                 ins->opcode += ovfops_op_map [src1->type];
1069                 break;
1070         case CEE_ADD_OVF:
1071         case CEE_ADD_OVF_UN:
1072         case CEE_MUL_OVF:
1073         case CEE_MUL_OVF_UN:
1074         case CEE_SUB_OVF:
1075         case CEE_SUB_OVF_UN:
1076                 ins->type = bin_num_table [src1->type] [src2->type];
1077                 ins->opcode += ovfops_op_map [src1->type];
1078                 if (ins->type == STACK_R8)
1079                         ins->type = STACK_INV;
1080                 break;
1081         case OP_LOAD_MEMBASE:
1082                 ins->type = STACK_PTR;
1083                 break;
1084         case OP_LOADI1_MEMBASE:
1085         case OP_LOADU1_MEMBASE:
1086         case OP_LOADI2_MEMBASE:
1087         case OP_LOADU2_MEMBASE:
1088         case OP_LOADI4_MEMBASE:
1089         case OP_LOADU4_MEMBASE:
1090                 ins->type = STACK_PTR;
1091                 break;
1092         case OP_LOADI8_MEMBASE:
1093                 ins->type = STACK_I8;
1094                 break;
1095         case OP_LOADR4_MEMBASE:
1096         case OP_LOADR8_MEMBASE:
1097                 ins->type = STACK_R8;
1098                 break;
1099         default:
1100                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1101                 break;
1102         }
1103
1104         if (ins->type == STACK_MP)
1105                 ins->klass = mono_defaults.object_class;
1106 }
1107
1108 static const char 
1109 ldind_type [] = {
1110         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1111 };
1112
1113 #if 0
1114
1115 static const char
1116 param_table [STACK_MAX] [STACK_MAX] = {
1117         {0},
1118 };
1119
1120 static int
1121 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1122         int i;
1123
1124         if (sig->hasthis) {
1125                 switch (args->type) {
1126                 case STACK_I4:
1127                 case STACK_I8:
1128                 case STACK_R8:
1129                 case STACK_VTYPE:
1130                 case STACK_INV:
1131                         return 0;
1132                 }
1133                 args++;
1134         }
1135         for (i = 0; i < sig->param_count; ++i) {
1136                 switch (args [i].type) {
1137                 case STACK_INV:
1138                         return 0;
1139                 case STACK_MP:
1140                         if (!sig->params [i]->byref)
1141                                 return 0;
1142                         continue;
1143                 case STACK_OBJ:
1144                         if (sig->params [i]->byref)
1145                                 return 0;
1146                         switch (sig->params [i]->type) {
1147                         case MONO_TYPE_CLASS:
1148                         case MONO_TYPE_STRING:
1149                         case MONO_TYPE_OBJECT:
1150                         case MONO_TYPE_SZARRAY:
1151                         case MONO_TYPE_ARRAY:
1152                                 break;
1153                         default:
1154                                 return 0;
1155                         }
1156                         continue;
1157                 case STACK_R8:
1158                         if (sig->params [i]->byref)
1159                                 return 0;
1160                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1161                                 return 0;
1162                         continue;
1163                 case STACK_PTR:
1164                 case STACK_I4:
1165                 case STACK_I8:
1166                 case STACK_VTYPE:
1167                         break;
1168                 }
1169                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1170                         return 0;*/
1171         }
1172         return 1;
1173 }
1174 #endif
1175
1176 /*
1177  * When we need a pointer to the current domain many times in a method, we
1178  * call mono_domain_get() once and we store the result in a local variable.
1179  * This function returns the variable that represents the MonoDomain*.
1180  */
1181 inline static MonoInst *
1182 mono_get_domainvar (MonoCompile *cfg)
1183 {
1184         if (!cfg->domainvar)
1185                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1186         return cfg->domainvar;
1187 }
1188
1189 /*
1190  * The got_var contains the address of the Global Offset Table when AOT 
1191  * compiling.
1192  */
1193 MonoInst *
1194 mono_get_got_var (MonoCompile *cfg)
1195 {
1196 #ifdef MONO_ARCH_NEED_GOT_VAR
1197         if (!cfg->compile_aot)
1198                 return NULL;
1199         if (!cfg->got_var) {
1200                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1201         }
1202         return cfg->got_var;
1203 #else
1204         return NULL;
1205 #endif
1206 }
1207
1208 static MonoInst *
1209 mono_get_vtable_var (MonoCompile *cfg)
1210 {
1211         g_assert (cfg->generic_sharing_context);
1212
1213         if (!cfg->rgctx_var) {
1214                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1215                 /* force the var to be stack allocated */
1216                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1217         }
1218
1219         return cfg->rgctx_var;
1220 }
1221
1222 static MonoType*
1223 type_from_stack_type (MonoInst *ins) {
1224         switch (ins->type) {
1225         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1226         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1227         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1228         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1229         case STACK_MP:
1230                 return &ins->klass->this_arg;
1231         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1232         case STACK_VTYPE: return &ins->klass->byval_arg;
1233         default:
1234                 g_error ("stack type %d to monotype not handled\n", ins->type);
1235         }
1236         return NULL;
1237 }
1238
1239 static G_GNUC_UNUSED int
1240 type_to_stack_type (MonoType *t)
1241 {
1242         t = mono_type_get_underlying_type (t);
1243         switch (t->type) {
1244         case MONO_TYPE_I1:
1245         case MONO_TYPE_U1:
1246         case MONO_TYPE_BOOLEAN:
1247         case MONO_TYPE_I2:
1248         case MONO_TYPE_U2:
1249         case MONO_TYPE_CHAR:
1250         case MONO_TYPE_I4:
1251         case MONO_TYPE_U4:
1252                 return STACK_I4;
1253         case MONO_TYPE_I:
1254         case MONO_TYPE_U:
1255         case MONO_TYPE_PTR:
1256         case MONO_TYPE_FNPTR:
1257                 return STACK_PTR;
1258         case MONO_TYPE_CLASS:
1259         case MONO_TYPE_STRING:
1260         case MONO_TYPE_OBJECT:
1261         case MONO_TYPE_SZARRAY:
1262         case MONO_TYPE_ARRAY:    
1263                 return STACK_OBJ;
1264         case MONO_TYPE_I8:
1265         case MONO_TYPE_U8:
1266                 return STACK_I8;
1267         case MONO_TYPE_R4:
1268         case MONO_TYPE_R8:
1269                 return STACK_R8;
1270         case MONO_TYPE_VALUETYPE:
1271         case MONO_TYPE_TYPEDBYREF:
1272                 return STACK_VTYPE;
1273         case MONO_TYPE_GENERICINST:
1274                 if (mono_type_generic_inst_is_valuetype (t))
1275                         return STACK_VTYPE;
1276                 else
1277                         return STACK_OBJ;
1278                 break;
1279         default:
1280                 g_assert_not_reached ();
1281         }
1282
1283         return -1;
1284 }
1285
1286 static MonoClass*
1287 array_access_to_klass (int opcode)
1288 {
1289         switch (opcode) {
1290         case CEE_LDELEM_U1:
1291                 return mono_defaults.byte_class;
1292         case CEE_LDELEM_U2:
1293                 return mono_defaults.uint16_class;
1294         case CEE_LDELEM_I:
1295         case CEE_STELEM_I:
1296                 return mono_defaults.int_class;
1297         case CEE_LDELEM_I1:
1298         case CEE_STELEM_I1:
1299                 return mono_defaults.sbyte_class;
1300         case CEE_LDELEM_I2:
1301         case CEE_STELEM_I2:
1302                 return mono_defaults.int16_class;
1303         case CEE_LDELEM_I4:
1304         case CEE_STELEM_I4:
1305                 return mono_defaults.int32_class;
1306         case CEE_LDELEM_U4:
1307                 return mono_defaults.uint32_class;
1308         case CEE_LDELEM_I8:
1309         case CEE_STELEM_I8:
1310                 return mono_defaults.int64_class;
1311         case CEE_LDELEM_R4:
1312         case CEE_STELEM_R4:
1313                 return mono_defaults.single_class;
1314         case CEE_LDELEM_R8:
1315         case CEE_STELEM_R8:
1316                 return mono_defaults.double_class;
1317         case CEE_LDELEM_REF:
1318         case CEE_STELEM_REF:
1319                 return mono_defaults.object_class;
1320         default:
1321                 g_assert_not_reached ();
1322         }
1323         return NULL;
1324 }
1325
1326 /*
1327  * We try to share variables when possible
1328  */
1329 static MonoInst *
1330 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1331 {
1332         MonoInst *res;
1333         int pos, vnum;
1334
1335         /* inlining can result in deeper stacks */ 
1336         if (slot >= cfg->header->max_stack)
1337                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1338
1339         pos = ins->type - 1 + slot * STACK_MAX;
1340
1341         switch (ins->type) {
1342         case STACK_I4:
1343         case STACK_I8:
1344         case STACK_R8:
1345         case STACK_PTR:
1346         case STACK_MP:
1347         case STACK_OBJ:
1348                 if ((vnum = cfg->intvars [pos]))
1349                         return cfg->varinfo [vnum];
1350                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1351                 cfg->intvars [pos] = res->inst_c0;
1352                 break;
1353         default:
1354                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1355         }
1356         return res;
1357 }
1358
1359 static void
1360 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1361 {
1362         /* 
1363          * Don't use this if a generic_context is set, since that means AOT can't
1364          * look up the method using just the image+token.
1365          * table == 0 means this is a reference made from a wrapper.
1366          */
1367         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1368                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1369                 jump_info_token->image = image;
1370                 jump_info_token->token = token;
1371                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1372         }
1373 }
1374
1375 /*
1376  * This function is called to handle items that are left on the evaluation stack
1377  * at basic block boundaries. What happens is that we save the values to local variables
1378  * and we reload them later when first entering the target basic block (with the
1379  * handle_loaded_temps () function).
1380  * A single joint point will use the same variables (stored in the array bb->out_stack or
1381  * bb->in_stack, if the basic block is before or after the joint point).
1382  *
1383  * This function needs to be called _before_ emitting the last instruction of
1384  * the bb (i.e. before emitting a branch).
1385  * If the stack merge fails at a join point, cfg->unverifiable is set.
1386  */
1387 static void
1388 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1389 {
1390         int i, bindex;
1391         MonoBasicBlock *bb = cfg->cbb;
1392         MonoBasicBlock *outb;
1393         MonoInst *inst, **locals;
1394         gboolean found;
1395
1396         if (!count)
1397                 return;
1398         if (cfg->verbose_level > 3)
1399                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1400         if (!bb->out_scount) {
1401                 bb->out_scount = count;
1402                 //printf ("bblock %d has out:", bb->block_num);
1403                 found = FALSE;
1404                 for (i = 0; i < bb->out_count; ++i) {
1405                         outb = bb->out_bb [i];
1406                         /* exception handlers are linked, but they should not be considered for stack args */
1407                         if (outb->flags & BB_EXCEPTION_HANDLER)
1408                                 continue;
1409                         //printf (" %d", outb->block_num);
1410                         if (outb->in_stack) {
1411                                 found = TRUE;
1412                                 bb->out_stack = outb->in_stack;
1413                                 break;
1414                         }
1415                 }
1416                 //printf ("\n");
1417                 if (!found) {
1418                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1419                         for (i = 0; i < count; ++i) {
1420                                 /* 
1421                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1422                                  * stack slot and if they are of the same type.
1423                                  * This won't cause conflicts since if 'local' is used to 
1424                                  * store one of the values in the in_stack of a bblock, then
1425                                  * the same variable will be used for the same outgoing stack 
1426                                  * slot as well. 
1427                                  * This doesn't work when inlining methods, since the bblocks
1428                                  * in the inlined methods do not inherit their in_stack from
1429                                  * the bblock they are inlined to. See bug #58863 for an
1430                                  * example.
1431                                  */
1432                                 if (cfg->inlined_method)
1433                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1434                                 else
1435                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1436                         }
1437                 }
1438         }
1439
1440         for (i = 0; i < bb->out_count; ++i) {
1441                 outb = bb->out_bb [i];
1442                 /* exception handlers are linked, but they should not be considered for stack args */
1443                 if (outb->flags & BB_EXCEPTION_HANDLER)
1444                         continue;
1445                 if (outb->in_scount) {
1446                         if (outb->in_scount != bb->out_scount) {
1447                                 cfg->unverifiable = TRUE;
1448                                 return;
1449                         }
1450                         continue; /* check they are the same locals */
1451                 }
1452                 outb->in_scount = count;
1453                 outb->in_stack = bb->out_stack;
1454         }
1455
1456         locals = bb->out_stack;
1457         cfg->cbb = bb;
1458         for (i = 0; i < count; ++i) {
1459                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1460                 inst->cil_code = sp [i]->cil_code;
1461                 sp [i] = locals [i];
1462                 if (cfg->verbose_level > 3)
1463                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1464         }
1465
1466         /*
1467          * It is possible that the out bblocks already have in_stack assigned, and
1468          * the in_stacks differ. In this case, we will store to all the different 
1469          * in_stacks.
1470          */
1471
1472         found = TRUE;
1473         bindex = 0;
1474         while (found) {
1475                 /* Find a bblock which has a different in_stack */
1476                 found = FALSE;
1477                 while (bindex < bb->out_count) {
1478                         outb = bb->out_bb [bindex];
1479                         /* exception handlers are linked, but they should not be considered for stack args */
1480                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1481                                 bindex++;
1482                                 continue;
1483                         }
1484                         if (outb->in_stack != locals) {
1485                                 for (i = 0; i < count; ++i) {
1486                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1487                                         inst->cil_code = sp [i]->cil_code;
1488                                         sp [i] = locals [i];
1489                                         if (cfg->verbose_level > 3)
1490                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1491                                 }
1492                                 locals = outb->in_stack;
1493                                 found = TRUE;
1494                                 break;
1495                         }
1496                         bindex ++;
1497                 }
1498         }
1499 }
1500
1501 /* Emit code which loads interface_offsets [klass->interface_id]
1502  * The array is stored in memory before vtable.
1503 */
1504 static void
1505 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1506 {
1507         if (cfg->compile_aot) {
1508                 int ioffset_reg = alloc_preg (cfg);
1509                 int iid_reg = alloc_preg (cfg);
1510
1511                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1512                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1513                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1514         }
1515         else {
1516                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1517         }
1518 }
1519
1520 static void
1521 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1522 {
1523         int ibitmap_reg = alloc_preg (cfg);
1524 #ifdef COMPRESSED_INTERFACE_BITMAP
1525         MonoInst *args [2];
1526         MonoInst *res, *ins;
1527         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1528         MONO_ADD_INS (cfg->cbb, ins);
1529         args [0] = ins;
1530         if (cfg->compile_aot)
1531                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1532         else
1533                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1534         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1535         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1536 #else
1537         int ibitmap_byte_reg = alloc_preg (cfg);
1538
1539         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1540
1541         if (cfg->compile_aot) {
1542                 int iid_reg = alloc_preg (cfg);
1543                 int shifted_iid_reg = alloc_preg (cfg);
1544                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1545                 int masked_iid_reg = alloc_preg (cfg);
1546                 int iid_one_bit_reg = alloc_preg (cfg);
1547                 int iid_bit_reg = alloc_preg (cfg);
1548                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1549                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1550                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1551                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1552                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1553                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1554                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1555                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1556         } else {
1557                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1558                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1559         }
1560 #endif
1561 }
1562
1563 /* 
1564  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1565  * stored in "klass_reg" implements the interface "klass".
1566  */
1567 static void
1568 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1569 {
1570         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1571 }
1572
1573 /* 
1574  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1575  * stored in "vtable_reg" implements the interface "klass".
1576  */
1577 static void
1578 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1579 {
1580         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1581 }
1582
1583 /* 
1584  * Emit code which checks whenever the interface id of @klass is smaller than
1585  * than the value given by max_iid_reg.
1586 */
1587 static void
1588 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1589                                                  MonoBasicBlock *false_target)
1590 {
1591         if (cfg->compile_aot) {
1592                 int iid_reg = alloc_preg (cfg);
1593                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1594                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1595         }
1596         else
1597                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1598         if (false_target)
1599                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1600         else
1601                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1602 }
1603
1604 /* Same as above, but obtains max_iid from a vtable */
1605 static void
1606 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1607                                                                  MonoBasicBlock *false_target)
1608 {
1609         int max_iid_reg = alloc_preg (cfg);
1610                 
1611         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1612         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1613 }
1614
1615 /* Same as above, but obtains max_iid from a klass */
1616 static void
1617 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1618                                                                  MonoBasicBlock *false_target)
1619 {
1620         int max_iid_reg = alloc_preg (cfg);
1621
1622         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1623         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1624 }
1625
1626 static void
1627 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1628 {
1629         int idepth_reg = alloc_preg (cfg);
1630         int stypes_reg = alloc_preg (cfg);
1631         int stype = alloc_preg (cfg);
1632
1633         mono_class_setup_supertypes (klass);
1634
1635         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1636                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1637                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1638                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1639         }
1640         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1641         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1642         if (klass_ins) {
1643                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1644         } else if (cfg->compile_aot) {
1645                 int const_reg = alloc_preg (cfg);
1646                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1647                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1648         } else {
1649                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1650         }
1651         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1652 }
1653
1654 static void
1655 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1656 {
1657         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1658 }
1659
1660 static void
1661 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1662 {
1663         int intf_reg = alloc_preg (cfg);
1664
1665         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1666         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1667         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1668         if (true_target)
1669                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1670         else
1671                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1672 }
1673
1674 /*
1675  * Variant of the above that takes a register to the class, not the vtable.
1676  */
1677 static void
1678 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1679 {
1680         int intf_bit_reg = alloc_preg (cfg);
1681
1682         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1683         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1684         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1685         if (true_target)
1686                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1687         else
1688                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1689 }
1690
1691 static inline void
1692 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1693 {
1694         if (klass_inst) {
1695                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1696         } else if (cfg->compile_aot) {
1697                 int const_reg = alloc_preg (cfg);
1698                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1699                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1700         } else {
1701                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1702         }
1703         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1704 }
1705
1706 static inline void
1707 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1708 {
1709         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1710 }
1711
1712 static inline void
1713 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1714 {
1715         if (cfg->compile_aot) {
1716                 int const_reg = alloc_preg (cfg);
1717                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1718                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1719         } else {
1720                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1721         }
1722         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1723 }
1724
1725 static void
1726 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1727         
1728 static void
1729 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1730 {
1731         if (klass->rank) {
1732                 int rank_reg = alloc_preg (cfg);
1733                 int eclass_reg = alloc_preg (cfg);
1734
1735                 g_assert (!klass_inst);
1736                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1737                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1738                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1739                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1740                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1741                 if (klass->cast_class == mono_defaults.object_class) {
1742                         int parent_reg = alloc_preg (cfg);
1743                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1744                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1745                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1746                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1747                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1748                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1749                 } else if (klass->cast_class == mono_defaults.enum_class) {
1750                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1751                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1752                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1753                 } else {
1754                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1755                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1756                 }
1757
1758                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1759                         /* Check that the object is a vector too */
1760                         int bounds_reg = alloc_preg (cfg);
1761                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1762                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1763                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1764                 }
1765         } else {
1766                 int idepth_reg = alloc_preg (cfg);
1767                 int stypes_reg = alloc_preg (cfg);
1768                 int stype = alloc_preg (cfg);
1769
1770                 mono_class_setup_supertypes (klass);
1771
1772                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1773                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1774                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1775                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1776                 }
1777                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1778                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1779                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1780         }
1781 }
1782
1783 static void
1784 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1785 {
1786         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1787 }
1788
1789 static void 
1790 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1791 {
1792         int val_reg;
1793
1794         g_assert (val == 0);
1795
1796         if (align == 0)
1797                 align = 4;
1798
1799         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1800                 switch (size) {
1801                 case 1:
1802                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1803                         return;
1804                 case 2:
1805                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1806                         return;
1807                 case 4:
1808                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1809                         return;
1810 #if SIZEOF_REGISTER == 8
1811                 case 8:
1812                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1813                         return;
1814 #endif
1815                 }
1816         }
1817
1818         val_reg = alloc_preg (cfg);
1819
1820         if (SIZEOF_REGISTER == 8)
1821                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1822         else
1823                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1824
1825         if (align < 4) {
1826                 /* This could be optimized further if neccesary */
1827                 while (size >= 1) {
1828                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1829                         offset += 1;
1830                         size -= 1;
1831                 }
1832                 return;
1833         }       
1834
1835 #if !NO_UNALIGNED_ACCESS
1836         if (SIZEOF_REGISTER == 8) {
1837                 if (offset % 8) {
1838                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1839                         offset += 4;
1840                         size -= 4;
1841                 }
1842                 while (size >= 8) {
1843                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1844                         offset += 8;
1845                         size -= 8;
1846                 }
1847         }       
1848 #endif
1849
1850         while (size >= 4) {
1851                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1852                 offset += 4;
1853                 size -= 4;
1854         }
1855         while (size >= 2) {
1856                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1857                 offset += 2;
1858                 size -= 2;
1859         }
1860         while (size >= 1) {
1861                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1862                 offset += 1;
1863                 size -= 1;
1864         }
1865 }
1866
1867 void 
1868 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1869 {
1870         int cur_reg;
1871
1872         if (align == 0)
1873                 align = 4;
1874
1875         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1876         g_assert (size < 10000);
1877
1878         if (align < 4) {
1879                 /* This could be optimized further if neccesary */
1880                 while (size >= 1) {
1881                         cur_reg = alloc_preg (cfg);
1882                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1883                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1884                         doffset += 1;
1885                         soffset += 1;
1886                         size -= 1;
1887                 }
1888         }
1889
1890 #if !NO_UNALIGNED_ACCESS
1891         if (SIZEOF_REGISTER == 8) {
1892                 while (size >= 8) {
1893                         cur_reg = alloc_preg (cfg);
1894                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1895                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1896                         doffset += 8;
1897                         soffset += 8;
1898                         size -= 8;
1899                 }
1900         }       
1901 #endif
1902
1903         while (size >= 4) {
1904                 cur_reg = alloc_preg (cfg);
1905                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1906                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1907                 doffset += 4;
1908                 soffset += 4;
1909                 size -= 4;
1910         }
1911         while (size >= 2) {
1912                 cur_reg = alloc_preg (cfg);
1913                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1914                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1915                 doffset += 2;
1916                 soffset += 2;
1917                 size -= 2;
1918         }
1919         while (size >= 1) {
1920                 cur_reg = alloc_preg (cfg);
1921                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1922                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1923                 doffset += 1;
1924                 soffset += 1;
1925                 size -= 1;
1926         }
1927 }
1928
1929 static void
1930 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1931 {
1932         MonoInst *ins, *c;
1933
1934         if (cfg->compile_aot) {
1935                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1936                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1937                 ins->sreg1 = sreg1;
1938                 ins->sreg2 = c->dreg;
1939                 MONO_ADD_INS (cfg->cbb, ins);
1940         } else {
1941                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1942                 ins->sreg1 = sreg1;
1943                 ins->inst_offset = mini_get_tls_offset (tls_key);
1944                 MONO_ADD_INS (cfg->cbb, ins);
1945         }
1946 }
1947
1948 /*
1949  * emit_push_lmf:
1950  *
1951  *   Emit IR to push the current LMF onto the LMF stack.
1952  */
1953 static void
1954 emit_push_lmf (MonoCompile *cfg)
1955 {
1956         /*
1957          * Emit IR to push the LMF:
1958          * lmf_addr = <lmf_addr from tls>
1959          * lmf->lmf_addr = lmf_addr
1960          * lmf->prev_lmf = *lmf_addr
1961          * *lmf_addr = lmf
1962          */
1963         int lmf_reg, prev_lmf_reg;
1964         MonoInst *ins, *lmf_ins;
1965
1966         if (!cfg->lmf_ir)
1967                 return;
1968
1969         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1970                 /* Load current lmf */
1971                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1972                 g_assert (lmf_ins);
1973                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1974                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1975                 lmf_reg = ins->dreg;
1976                 /* Save previous_lmf */
1977                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1978                 /* Set new LMF */
1979                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1980         } else {
1981                 /*
1982                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1983                  */
1984                 if (!cfg->lmf_addr_var)
1985                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1986
1987 #ifdef HOST_WIN32
1988                 ins = mono_get_jit_tls_intrinsic (cfg);
1989                 if (ins) {
1990                         int jit_tls_dreg = ins->dreg;
1991
1992                         MONO_ADD_INS (cfg->cbb, ins);
1993                         lmf_reg = alloc_preg (cfg);
1994                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
1995                 } else {
1996                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
1997                 }
1998 #else
1999                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2000                 if (lmf_ins) {
2001                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2002                 } else {
2003 #ifdef TARGET_IOS
2004                         MonoInst *args [16], *jit_tls_ins, *ins;
2005
2006                         /* Inline mono_get_lmf_addr () */
2007                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2008
2009                         /* Load mono_jit_tls_id */
2010                         EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2011                         /* call pthread_getspecific () */
2012                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2013                         /* lmf_addr = &jit_tls->lmf */
2014                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2015                         lmf_ins = ins;
2016 #else
2017                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2018 #endif
2019                 }
2020 #endif
2021                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2022
2023                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2024                 lmf_reg = ins->dreg;
2025
2026                 prev_lmf_reg = alloc_preg (cfg);
2027                 /* Save previous_lmf */
2028                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2029                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2030                 /* Set new lmf */
2031                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2032         }
2033 }
2034
2035 /*
2036  * emit_pop_lmf:
2037  *
2038  *   Emit IR to pop the current LMF from the LMF stack.
2039  */
2040 static void
2041 emit_pop_lmf (MonoCompile *cfg)
2042 {
2043         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2044         MonoInst *ins;
2045
2046         if (!cfg->lmf_ir)
2047                 return;
2048
2049         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2050         lmf_reg = ins->dreg;
2051
2052         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2053                 /* Load previous_lmf */
2054                 prev_lmf_reg = alloc_preg (cfg);
2055                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2056                 /* Set new LMF */
2057                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2058         } else {
2059                 /*
2060                  * Emit IR to pop the LMF:
2061                  * *(lmf->lmf_addr) = lmf->prev_lmf
2062                  */
2063                 /* This could be called before emit_push_lmf () */
2064                 if (!cfg->lmf_addr_var)
2065                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2066                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2067
2068                 prev_lmf_reg = alloc_preg (cfg);
2069                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2070                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2071         }
2072 }
2073
2074 static void
2075 emit_instrumentation_call (MonoCompile *cfg, void *func)
2076 {
2077         MonoInst *iargs [1];
2078
2079         /*
2080          * Avoid instrumenting inlined methods since it can
2081          * distort profiling results.
2082          */
2083         if (cfg->method != cfg->current_method)
2084                 return;
2085
2086         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2087                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2088                 mono_emit_jit_icall (cfg, func, iargs);
2089         }
2090 }
2091
2092 static int
2093 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2094 {
2095         if (type->byref)
2096                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2097
2098 handle_enum:
2099         type = mini_get_basic_type_from_generic (gsctx, type);
2100         type = mini_replace_type (type);
2101         switch (type->type) {
2102         case MONO_TYPE_VOID:
2103                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2104         case MONO_TYPE_I1:
2105         case MONO_TYPE_U1:
2106         case MONO_TYPE_BOOLEAN:
2107         case MONO_TYPE_I2:
2108         case MONO_TYPE_U2:
2109         case MONO_TYPE_CHAR:
2110         case MONO_TYPE_I4:
2111         case MONO_TYPE_U4:
2112                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2113         case MONO_TYPE_I:
2114         case MONO_TYPE_U:
2115         case MONO_TYPE_PTR:
2116         case MONO_TYPE_FNPTR:
2117                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2118         case MONO_TYPE_CLASS:
2119         case MONO_TYPE_STRING:
2120         case MONO_TYPE_OBJECT:
2121         case MONO_TYPE_SZARRAY:
2122         case MONO_TYPE_ARRAY:    
2123                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2124         case MONO_TYPE_I8:
2125         case MONO_TYPE_U8:
2126                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2127         case MONO_TYPE_R4:
2128         case MONO_TYPE_R8:
2129                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2130         case MONO_TYPE_VALUETYPE:
2131                 if (type->data.klass->enumtype) {
2132                         type = mono_class_enum_basetype (type->data.klass);
2133                         goto handle_enum;
2134                 } else
2135                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2136         case MONO_TYPE_TYPEDBYREF:
2137                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2138         case MONO_TYPE_GENERICINST:
2139                 type = &type->data.generic_class->container_class->byval_arg;
2140                 goto handle_enum;
2141         case MONO_TYPE_VAR:
2142         case MONO_TYPE_MVAR:
2143                 /* gsharedvt */
2144                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2145         default:
2146                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2147         }
2148         return -1;
2149 }
2150
2151 /*
2152  * target_type_is_incompatible:
2153  * @cfg: MonoCompile context
2154  *
2155  * Check that the item @arg on the evaluation stack can be stored
2156  * in the target type (can be a local, or field, etc).
2157  * The cfg arg can be used to check if we need verification or just
2158  * validity checks.
2159  *
2160  * Returns: non-0 value if arg can't be stored on a target.
2161  */
2162 static int
2163 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2164 {
2165         MonoType *simple_type;
2166         MonoClass *klass;
2167
2168         target = mini_replace_type (target);
2169         if (target->byref) {
2170                 /* FIXME: check that the pointed to types match */
2171                 if (arg->type == STACK_MP)
2172                         return arg->klass != mono_class_from_mono_type (target);
2173                 if (arg->type == STACK_PTR)
2174                         return 0;
2175                 return 1;
2176         }
2177
2178         simple_type = mono_type_get_underlying_type (target);
2179         switch (simple_type->type) {
2180         case MONO_TYPE_VOID:
2181                 return 1;
2182         case MONO_TYPE_I1:
2183         case MONO_TYPE_U1:
2184         case MONO_TYPE_BOOLEAN:
2185         case MONO_TYPE_I2:
2186         case MONO_TYPE_U2:
2187         case MONO_TYPE_CHAR:
2188         case MONO_TYPE_I4:
2189         case MONO_TYPE_U4:
2190                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2191                         return 1;
2192                 return 0;
2193         case MONO_TYPE_PTR:
2194                 /* STACK_MP is needed when setting pinned locals */
2195                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2196                         return 1;
2197                 return 0;
2198         case MONO_TYPE_I:
2199         case MONO_TYPE_U:
2200         case MONO_TYPE_FNPTR:
2201                 /* 
2202                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2203                  * in native int. (#688008).
2204                  */
2205                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2206                         return 1;
2207                 return 0;
2208         case MONO_TYPE_CLASS:
2209         case MONO_TYPE_STRING:
2210         case MONO_TYPE_OBJECT:
2211         case MONO_TYPE_SZARRAY:
2212         case MONO_TYPE_ARRAY:    
2213                 if (arg->type != STACK_OBJ)
2214                         return 1;
2215                 /* FIXME: check type compatibility */
2216                 return 0;
2217         case MONO_TYPE_I8:
2218         case MONO_TYPE_U8:
2219                 if (arg->type != STACK_I8)
2220                         return 1;
2221                 return 0;
2222         case MONO_TYPE_R4:
2223         case MONO_TYPE_R8:
2224                 if (arg->type != STACK_R8)
2225                         return 1;
2226                 return 0;
2227         case MONO_TYPE_VALUETYPE:
2228                 if (arg->type != STACK_VTYPE)
2229                         return 1;
2230                 klass = mono_class_from_mono_type (simple_type);
2231                 if (klass != arg->klass)
2232                         return 1;
2233                 return 0;
2234         case MONO_TYPE_TYPEDBYREF:
2235                 if (arg->type != STACK_VTYPE)
2236                         return 1;
2237                 klass = mono_class_from_mono_type (simple_type);
2238                 if (klass != arg->klass)
2239                         return 1;
2240                 return 0;
2241         case MONO_TYPE_GENERICINST:
2242                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2243                         if (arg->type != STACK_VTYPE)
2244                                 return 1;
2245                         klass = mono_class_from_mono_type (simple_type);
2246                         if (klass != arg->klass)
2247                                 return 1;
2248                         return 0;
2249                 } else {
2250                         if (arg->type != STACK_OBJ)
2251                                 return 1;
2252                         /* FIXME: check type compatibility */
2253                         return 0;
2254                 }
2255         case MONO_TYPE_VAR:
2256         case MONO_TYPE_MVAR:
2257                 g_assert (cfg->generic_sharing_context);
2258                 if (mini_type_var_is_vt (cfg, simple_type)) {
2259                         if (arg->type != STACK_VTYPE)
2260                                 return 1;
2261                 } else {
2262                         if (arg->type != STACK_OBJ)
2263                                 return 1;
2264                 }
2265                 return 0;
2266         default:
2267                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2268         }
2269         return 1;
2270 }
2271
2272 /*
2273  * Prepare arguments for passing to a function call.
2274  * Return a non-zero value if the arguments can't be passed to the given
2275  * signature.
2276  * The type checks are not yet complete and some conversions may need
2277  * casts on 32 or 64 bit architectures.
2278  *
2279  * FIXME: implement this using target_type_is_incompatible ()
2280  */
2281 static int
2282 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2283 {
2284         MonoType *simple_type;
2285         int i;
2286
2287         if (sig->hasthis) {
2288                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2289                         return 1;
2290                 args++;
2291         }
2292         for (i = 0; i < sig->param_count; ++i) {
2293                 if (sig->params [i]->byref) {
2294                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2295                                 return 1;
2296                         continue;
2297                 }
2298                 simple_type = sig->params [i];
2299                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2300 handle_enum:
2301                 switch (simple_type->type) {
2302                 case MONO_TYPE_VOID:
2303                         return 1;
2304                         continue;
2305                 case MONO_TYPE_I1:
2306                 case MONO_TYPE_U1:
2307                 case MONO_TYPE_BOOLEAN:
2308                 case MONO_TYPE_I2:
2309                 case MONO_TYPE_U2:
2310                 case MONO_TYPE_CHAR:
2311                 case MONO_TYPE_I4:
2312                 case MONO_TYPE_U4:
2313                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2314                                 return 1;
2315                         continue;
2316                 case MONO_TYPE_I:
2317                 case MONO_TYPE_U:
2318                 case MONO_TYPE_PTR:
2319                 case MONO_TYPE_FNPTR:
2320                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2321                                 return 1;
2322                         continue;
2323                 case MONO_TYPE_CLASS:
2324                 case MONO_TYPE_STRING:
2325                 case MONO_TYPE_OBJECT:
2326                 case MONO_TYPE_SZARRAY:
2327                 case MONO_TYPE_ARRAY:    
2328                         if (args [i]->type != STACK_OBJ)
2329                                 return 1;
2330                         continue;
2331                 case MONO_TYPE_I8:
2332                 case MONO_TYPE_U8:
2333                         if (args [i]->type != STACK_I8)
2334                                 return 1;
2335                         continue;
2336                 case MONO_TYPE_R4:
2337                 case MONO_TYPE_R8:
2338                         if (args [i]->type != STACK_R8)
2339                                 return 1;
2340                         continue;
2341                 case MONO_TYPE_VALUETYPE:
2342                         if (simple_type->data.klass->enumtype) {
2343                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2344                                 goto handle_enum;
2345                         }
2346                         if (args [i]->type != STACK_VTYPE)
2347                                 return 1;
2348                         continue;
2349                 case MONO_TYPE_TYPEDBYREF:
2350                         if (args [i]->type != STACK_VTYPE)
2351                                 return 1;
2352                         continue;
2353                 case MONO_TYPE_GENERICINST:
2354                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2355                         goto handle_enum;
2356                 case MONO_TYPE_VAR:
2357                 case MONO_TYPE_MVAR:
2358                         /* gsharedvt */
2359                         if (args [i]->type != STACK_VTYPE)
2360                                 return 1;
2361                         continue;
2362                 default:
2363                         g_error ("unknown type 0x%02x in check_call_signature",
2364                                  simple_type->type);
2365                 }
2366         }
2367         return 0;
2368 }
2369
2370 static int
2371 callvirt_to_call (int opcode)
2372 {
2373         switch (opcode) {
2374         case OP_CALL_MEMBASE:
2375                 return OP_CALL;
2376         case OP_VOIDCALL_MEMBASE:
2377                 return OP_VOIDCALL;
2378         case OP_FCALL_MEMBASE:
2379                 return OP_FCALL;
2380         case OP_VCALL_MEMBASE:
2381                 return OP_VCALL;
2382         case OP_LCALL_MEMBASE:
2383                 return OP_LCALL;
2384         default:
2385                 g_assert_not_reached ();
2386         }
2387
2388         return -1;
2389 }
2390
2391 /* Either METHOD or IMT_ARG needs to be set */
2392 static void
2393 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2394 {
2395         int method_reg;
2396
2397         if (COMPILE_LLVM (cfg)) {
2398                 method_reg = alloc_preg (cfg);
2399
2400                 if (imt_arg) {
2401                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2402                 } else if (cfg->compile_aot) {
2403                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2404                 } else {
2405                         MonoInst *ins;
2406                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2407                         ins->inst_p0 = method;
2408                         ins->dreg = method_reg;
2409                         MONO_ADD_INS (cfg->cbb, ins);
2410                 }
2411
2412 #ifdef ENABLE_LLVM
2413                 call->imt_arg_reg = method_reg;
2414 #endif
2415 #ifdef MONO_ARCH_IMT_REG
2416         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2417 #else
2418         /* Need this to keep the IMT arg alive */
2419         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2420 #endif
2421                 return;
2422         }
2423
2424 #ifdef MONO_ARCH_IMT_REG
2425         method_reg = alloc_preg (cfg);
2426
2427         if (imt_arg) {
2428                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2429         } else if (cfg->compile_aot) {
2430                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2431         } else {
2432                 MonoInst *ins;
2433                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2434                 ins->inst_p0 = method;
2435                 ins->dreg = method_reg;
2436                 MONO_ADD_INS (cfg->cbb, ins);
2437         }
2438
2439         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2440 #else
2441         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2442 #endif
2443 }
2444
2445 static MonoJumpInfo *
2446 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2447 {
2448         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2449
2450         ji->ip.i = ip;
2451         ji->type = type;
2452         ji->data.target = target;
2453
2454         return ji;
2455 }
2456
2457 static int
2458 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2459 {
2460         if (cfg->generic_sharing_context)
2461                 return mono_class_check_context_used (klass);
2462         else
2463                 return 0;
2464 }
2465
2466 static int
2467 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2468 {
2469         if (cfg->generic_sharing_context)
2470                 return mono_method_check_context_used (method);
2471         else
2472                 return 0;
2473 }
2474
2475 /*
2476  * check_method_sharing:
2477  *
2478  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2479  */
2480 static void
2481 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2482 {
2483         gboolean pass_vtable = FALSE;
2484         gboolean pass_mrgctx = FALSE;
2485
2486         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2487                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2488                 gboolean sharable = FALSE;
2489
2490                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2491                         sharable = TRUE;
2492                 } else {
2493                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2494                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2495                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2496
2497                         sharable = sharing_enabled && context_sharable;
2498                 }
2499
2500                 /*
2501                  * Pass vtable iff target method might
2502                  * be shared, which means that sharing
2503                  * is enabled for its class and its
2504                  * context is sharable (and it's not a
2505                  * generic method).
2506                  */
2507                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2508                         pass_vtable = TRUE;
2509         }
2510
2511         if (mini_method_get_context (cmethod) &&
2512                 mini_method_get_context (cmethod)->method_inst) {
2513                 g_assert (!pass_vtable);
2514
2515                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2516                         pass_mrgctx = TRUE;
2517                 } else {
2518                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2519                         MonoGenericContext *context = mini_method_get_context (cmethod);
2520                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2521
2522                         if (sharing_enabled && context_sharable)
2523                                 pass_mrgctx = TRUE;
2524                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2525                                 pass_mrgctx = TRUE;
2526                 }
2527         }
2528
2529         if (out_pass_vtable)
2530                 *out_pass_vtable = pass_vtable;
2531         if (out_pass_mrgctx)
2532                 *out_pass_mrgctx = pass_mrgctx;
2533 }
2534
2535 inline static MonoCallInst *
2536 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2537                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2538 {
2539         MonoType *sig_ret;
2540         MonoCallInst *call;
2541 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2542         int i;
2543 #endif
2544
2545         if (tail) {
2546                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2547
2548                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2549         } else
2550                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2551
2552         call->args = args;
2553         call->signature = sig;
2554         call->rgctx_reg = rgctx;
2555         sig_ret = mini_replace_type (sig->ret);
2556
2557         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2558
2559         if (tail) {
2560                 if (mini_type_is_vtype (cfg, sig_ret)) {
2561                         call->vret_var = cfg->vret_addr;
2562                         //g_assert_not_reached ();
2563                 }
2564         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2565                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2566                 MonoInst *loada;
2567
2568                 temp->backend.is_pinvoke = sig->pinvoke;
2569
2570                 /*
2571                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2572                  * address of return value to increase optimization opportunities.
2573                  * Before vtype decomposition, the dreg of the call ins itself represents the
2574                  * fact the call modifies the return value. After decomposition, the call will
2575                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2576                  * will be transformed into an LDADDR.
2577                  */
2578                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2579                 loada->dreg = alloc_preg (cfg);
2580                 loada->inst_p0 = temp;
2581                 /* We reference the call too since call->dreg could change during optimization */
2582                 loada->inst_p1 = call;
2583                 MONO_ADD_INS (cfg->cbb, loada);
2584
2585                 call->inst.dreg = temp->dreg;
2586
2587                 call->vret_var = loada;
2588         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2589                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2590
2591 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2592         if (COMPILE_SOFT_FLOAT (cfg)) {
2593                 /* 
2594                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2595                  * an icall, but that cannot be done during the call sequence since it would clobber
2596                  * the call registers + the stack. So we do it before emitting the call.
2597                  */
2598                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2599                         MonoType *t;
2600                         MonoInst *in = call->args [i];
2601
2602                         if (i >= sig->hasthis)
2603                                 t = sig->params [i - sig->hasthis];
2604                         else
2605                                 t = &mono_defaults.int_class->byval_arg;
2606                         t = mono_type_get_underlying_type (t);
2607
2608                         if (!t->byref && t->type == MONO_TYPE_R4) {
2609                                 MonoInst *iargs [1];
2610                                 MonoInst *conv;
2611
2612                                 iargs [0] = in;
2613                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2614
2615                                 /* The result will be in an int vreg */
2616                                 call->args [i] = conv;
2617                         }
2618                 }
2619         }
2620 #endif
2621
2622         call->need_unbox_trampoline = unbox_trampoline;
2623
2624 #ifdef ENABLE_LLVM
2625         if (COMPILE_LLVM (cfg))
2626                 mono_llvm_emit_call (cfg, call);
2627         else
2628                 mono_arch_emit_call (cfg, call);
2629 #else
2630         mono_arch_emit_call (cfg, call);
2631 #endif
2632
2633         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2634         cfg->flags |= MONO_CFG_HAS_CALLS;
2635         
2636         return call;
2637 }
2638
2639 static void
2640 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2641 {
2642 #ifdef MONO_ARCH_RGCTX_REG
2643         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2644         cfg->uses_rgctx_reg = TRUE;
2645         call->rgctx_reg = TRUE;
2646 #ifdef ENABLE_LLVM
2647         call->rgctx_arg_reg = rgctx_reg;
2648 #endif
2649 #else
2650         NOT_IMPLEMENTED;
2651 #endif
2652 }       
2653
2654 inline static MonoInst*
2655 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2656 {
2657         MonoCallInst *call;
2658         MonoInst *ins;
2659         int rgctx_reg = -1;
2660         gboolean check_sp = FALSE;
2661
2662         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2663                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2664
2665                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2666                         check_sp = TRUE;
2667         }
2668
2669         if (rgctx_arg) {
2670                 rgctx_reg = mono_alloc_preg (cfg);
2671                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2672         }
2673
2674         if (check_sp) {
2675                 if (!cfg->stack_inbalance_var)
2676                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2677
2678                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2679                 ins->dreg = cfg->stack_inbalance_var->dreg;
2680                 MONO_ADD_INS (cfg->cbb, ins);
2681         }
2682
2683         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2684
2685         call->inst.sreg1 = addr->dreg;
2686
2687         if (imt_arg)
2688                 emit_imt_argument (cfg, call, NULL, imt_arg);
2689
2690         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2691
2692         if (check_sp) {
2693                 int sp_reg;
2694
2695                 sp_reg = mono_alloc_preg (cfg);
2696
2697                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2698                 ins->dreg = sp_reg;
2699                 MONO_ADD_INS (cfg->cbb, ins);
2700
2701                 /* Restore the stack so we don't crash when throwing the exception */
2702                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2703                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2704                 MONO_ADD_INS (cfg->cbb, ins);
2705
2706                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2707                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2708         }
2709
2710         if (rgctx_arg)
2711                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2712
2713         return (MonoInst*)call;
2714 }
2715
2716 static MonoInst*
2717 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2718
2719 static MonoInst*
2720 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2721 static MonoInst*
2722 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2723
2724 static MonoInst*
2725 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2726                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2727 {
2728 #ifndef DISABLE_REMOTING
2729         gboolean might_be_remote = FALSE;
2730 #endif
2731         gboolean virtual = this != NULL;
2732         gboolean enable_for_aot = TRUE;
2733         int context_used;
2734         MonoCallInst *call;
2735         int rgctx_reg = 0;
2736         gboolean need_unbox_trampoline;
2737
2738         if (!sig)
2739                 sig = mono_method_signature (method);
2740
2741         if (rgctx_arg) {
2742                 rgctx_reg = mono_alloc_preg (cfg);
2743                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2744         }
2745
2746         if (method->string_ctor) {
2747                 /* Create the real signature */
2748                 /* FIXME: Cache these */
2749                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2750                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2751
2752                 sig = ctor_sig;
2753         }
2754
2755         context_used = mini_method_check_context_used (cfg, method);
2756
2757 #ifndef DISABLE_REMOTING
2758         might_be_remote = this && sig->hasthis &&
2759                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2760                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2761
2762         if (might_be_remote && context_used) {
2763                 MonoInst *addr;
2764
2765                 g_assert (cfg->generic_sharing_context);
2766
2767                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2768
2769                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2770         }
2771 #endif
2772
2773         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2774
2775         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2776
2777 #ifndef DISABLE_REMOTING
2778         if (might_be_remote)
2779                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2780         else
2781 #endif
2782                 call->method = method;
2783         call->inst.flags |= MONO_INST_HAS_METHOD;
2784         call->inst.inst_left = this;
2785         call->tail_call = tail;
2786
2787         if (virtual) {
2788                 int vtable_reg, slot_reg, this_reg;
2789                 int offset;
2790
2791                 this_reg = this->dreg;
2792
2793                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2794                         MonoInst *dummy_use;
2795
2796                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2797
2798                         /* Make a call to delegate->invoke_impl */
2799                         call->inst.inst_basereg = this_reg;
2800                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2801                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2802
2803                         /* We must emit a dummy use here because the delegate trampoline will
2804                         replace the 'this' argument with the delegate target making this activation
2805                         no longer a root for the delegate.
2806                         This is an issue for delegates that target collectible code such as dynamic
2807                         methods of GC'able assemblies.
2808
2809                         For a test case look into #667921.
2810
2811                         FIXME: a dummy use is not the best way to do it as the local register allocator
2812                         will put it on a caller save register and spil it around the call. 
2813                         Ideally, we would either put it on a callee save register or only do the store part.  
2814                          */
2815                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2816
2817                         return (MonoInst*)call;
2818                 }
2819
2820                 if ((!cfg->compile_aot || enable_for_aot) && 
2821                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2822                          (MONO_METHOD_IS_FINAL (method) &&
2823                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2824                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2825                         /* 
2826                          * the method is not virtual, we just need to ensure this is not null
2827                          * and then we can call the method directly.
2828                          */
2829 #ifndef DISABLE_REMOTING
2830                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2831                                 /* 
2832                                  * The check above ensures method is not gshared, this is needed since
2833                                  * gshared methods can't have wrappers.
2834                                  */
2835                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2836                         }
2837 #endif
2838
2839                         if (!method->string_ctor)
2840                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2841
2842                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2843                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2844                         /*
2845                          * the method is virtual, but we can statically dispatch since either
2846                          * it's class or the method itself are sealed.
2847                          * But first we need to ensure it's not a null reference.
2848                          */
2849                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2850
2851                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2852                 } else {
2853                         vtable_reg = alloc_preg (cfg);
2854                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2855                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2856                                 slot_reg = -1;
2857                                 if (mono_use_imt) {
2858                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2859                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2860                                         slot_reg = vtable_reg;
2861                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2862                                 }
2863                                 if (slot_reg == -1) {
2864                                         slot_reg = alloc_preg (cfg);
2865                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2866                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2867                                 }
2868                         } else {
2869                                 slot_reg = vtable_reg;
2870                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2871                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2872                                 if (imt_arg) {
2873                                         g_assert (mono_method_signature (method)->generic_param_count);
2874                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2875                                 }
2876                         }
2877
2878                         call->inst.sreg1 = slot_reg;
2879                         call->inst.inst_offset = offset;
2880                         call->virtual = TRUE;
2881                 }
2882         }
2883
2884         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2885
2886         if (rgctx_arg)
2887                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2888
2889         return (MonoInst*)call;
2890 }
2891
2892 MonoInst*
2893 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2894 {
2895         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2896 }
2897
2898 MonoInst*
2899 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2900                                            MonoInst **args)
2901 {
2902         MonoCallInst *call;
2903
2904         g_assert (sig);
2905
2906         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2907         call->fptr = func;
2908
2909         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2910
2911         return (MonoInst*)call;
2912 }
2913
2914 MonoInst*
2915 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2916 {
2917         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2918
2919         g_assert (info);
2920
2921         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2922 }
2923
2924 /*
2925  * mono_emit_abs_call:
2926  *
2927  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2928  */
2929 inline static MonoInst*
2930 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2931                                         MonoMethodSignature *sig, MonoInst **args)
2932 {
2933         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2934         MonoInst *ins;
2935
2936         /* 
2937          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2938          * handle it.
2939          */
2940         if (cfg->abs_patches == NULL)
2941                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2942         g_hash_table_insert (cfg->abs_patches, ji, ji);
2943         ins = mono_emit_native_call (cfg, ji, sig, args);
2944         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2945         return ins;
2946 }
2947  
2948 static MonoInst*
2949 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2950 {
2951         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2952                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2953                         int widen_op = -1;
2954
2955                         /* 
2956                          * Native code might return non register sized integers 
2957                          * without initializing the upper bits.
2958                          */
2959                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2960                         case OP_LOADI1_MEMBASE:
2961                                 widen_op = OP_ICONV_TO_I1;
2962                                 break;
2963                         case OP_LOADU1_MEMBASE:
2964                                 widen_op = OP_ICONV_TO_U1;
2965                                 break;
2966                         case OP_LOADI2_MEMBASE:
2967                                 widen_op = OP_ICONV_TO_I2;
2968                                 break;
2969                         case OP_LOADU2_MEMBASE:
2970                                 widen_op = OP_ICONV_TO_U2;
2971                                 break;
2972                         default:
2973                                 break;
2974                         }
2975
2976                         if (widen_op != -1) {
2977                                 int dreg = alloc_preg (cfg);
2978                                 MonoInst *widen;
2979
2980                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2981                                 widen->type = ins->type;
2982                                 ins = widen;
2983                         }
2984                 }
2985         }
2986
2987         return ins;
2988 }
2989
2990 static MonoMethod*
2991 get_memcpy_method (void)
2992 {
2993         static MonoMethod *memcpy_method = NULL;
2994         if (!memcpy_method) {
2995                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2996                 if (!memcpy_method)
2997                         g_error ("Old corlib found. Install a new one");
2998         }
2999         return memcpy_method;
3000 }
3001
3002 static void
3003 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3004 {
3005         MonoClassField *field;
3006         gpointer iter = NULL;
3007
3008         while ((field = mono_class_get_fields (klass, &iter))) {
3009                 int foffset;
3010
3011                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3012                         continue;
3013                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3014                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
3015                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3016                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3017                 } else {
3018                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3019                         if (field_class->has_references)
3020                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3021                 }
3022         }
3023 }
3024
3025 static void
3026 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3027 {
3028         int card_table_shift_bits;
3029         gpointer card_table_mask;
3030         guint8 *card_table;
3031         MonoInst *dummy_use;
3032         int nursery_shift_bits;
3033         size_t nursery_size;
3034         gboolean has_card_table_wb = FALSE;
3035
3036         if (!cfg->gen_write_barriers)
3037                 return;
3038
3039         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3040
3041         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3042
3043 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3044         has_card_table_wb = TRUE;
3045 #endif
3046
3047         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3048                 MonoInst *wbarrier;
3049
3050                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3051                 wbarrier->sreg1 = ptr->dreg;
3052                 wbarrier->sreg2 = value->dreg;
3053                 MONO_ADD_INS (cfg->cbb, wbarrier);
3054         } else if (card_table) {
3055                 int offset_reg = alloc_preg (cfg);
3056                 int card_reg  = alloc_preg (cfg);
3057                 MonoInst *ins;
3058
3059                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3060                 if (card_table_mask)
3061                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3062
3063                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3064                  * IMM's larger than 32bits.
3065                  */
3066                 if (cfg->compile_aot) {
3067                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3068                 } else {
3069                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3070                         ins->inst_p0 = card_table;
3071                         ins->dreg = card_reg;
3072                         MONO_ADD_INS (cfg->cbb, ins);
3073                 }
3074
3075                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3076                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3077         } else {
3078                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3079                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3080         }
3081
3082         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3083 }
3084
3085 static gboolean
3086 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3087 {
3088         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3089         unsigned need_wb = 0;
3090
3091         if (align == 0)
3092                 align = 4;
3093
3094         /*types with references can't have alignment smaller than sizeof(void*) */
3095         if (align < SIZEOF_VOID_P)
3096                 return FALSE;
3097
3098         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3099         if (size > 32 * SIZEOF_VOID_P)
3100                 return FALSE;
3101
3102         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3103
3104         /* We don't unroll more than 5 stores to avoid code bloat. */
3105         if (size > 5 * SIZEOF_VOID_P) {
3106                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3107                 size += (SIZEOF_VOID_P - 1);
3108                 size &= ~(SIZEOF_VOID_P - 1);
3109
3110                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3111                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3112                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3113                 return TRUE;
3114         }
3115
3116         destreg = iargs [0]->dreg;
3117         srcreg = iargs [1]->dreg;
3118         offset = 0;
3119
3120         dest_ptr_reg = alloc_preg (cfg);
3121         tmp_reg = alloc_preg (cfg);
3122
3123         /*tmp = dreg*/
3124         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3125
3126         while (size >= SIZEOF_VOID_P) {
3127                 MonoInst *load_inst;
3128                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3129                 load_inst->dreg = tmp_reg;
3130                 load_inst->inst_basereg = srcreg;
3131                 load_inst->inst_offset = offset;
3132                 MONO_ADD_INS (cfg->cbb, load_inst);
3133
3134                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3135
3136                 if (need_wb & 0x1)
3137                         emit_write_barrier (cfg, iargs [0], load_inst);
3138
3139                 offset += SIZEOF_VOID_P;
3140                 size -= SIZEOF_VOID_P;
3141                 need_wb >>= 1;
3142
3143                 /*tmp += sizeof (void*)*/
3144                 if (size >= SIZEOF_VOID_P) {
3145                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3146                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3147                 }
3148         }
3149
3150         /* Those cannot be references since size < sizeof (void*) */
3151         while (size >= 4) {
3152                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3153                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3154                 offset += 4;
3155                 size -= 4;
3156         }
3157
3158         while (size >= 2) {
3159                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3160                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3161                 offset += 2;
3162                 size -= 2;
3163         }
3164
3165         while (size >= 1) {
3166                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3167                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3168                 offset += 1;
3169                 size -= 1;
3170         }
3171
3172         return TRUE;
3173 }
3174
3175 /*
3176  * Emit code to copy a valuetype of type @klass whose address is stored in
3177  * @src->dreg to memory whose address is stored at @dest->dreg.
3178  */
3179 void
3180 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3181 {
3182         MonoInst *iargs [4];
3183         int context_used, n;
3184         guint32 align = 0;
3185         MonoMethod *memcpy_method;
3186         MonoInst *size_ins = NULL;
3187         MonoInst *memcpy_ins = NULL;
3188
3189         g_assert (klass);
3190         /*
3191          * This check breaks with spilled vars... need to handle it during verification anyway.
3192          * g_assert (klass && klass == src->klass && klass == dest->klass);
3193          */
3194
3195         if (mini_is_gsharedvt_klass (cfg, klass)) {
3196                 g_assert (!native);
3197                 context_used = mini_class_check_context_used (cfg, klass);
3198                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3199                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3200         }
3201
3202         if (native)
3203                 n = mono_class_native_size (klass, &align);
3204         else
3205                 n = mono_class_value_size (klass, &align);
3206
3207         /* if native is true there should be no references in the struct */
3208         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3209                 /* Avoid barriers when storing to the stack */
3210                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3211                           (dest->opcode == OP_LDADDR))) {
3212                         int context_used;
3213
3214                         iargs [0] = dest;
3215                         iargs [1] = src;
3216
3217                         context_used = mini_class_check_context_used (cfg, klass);
3218
3219                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3220                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3221                                 return;
3222                         } else if (context_used) {
3223                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3224                         }  else {
3225                                 if (cfg->compile_aot) {
3226                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3227                                 } else {
3228                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3229                                         mono_class_compute_gc_descriptor (klass);
3230                                 }
3231                         }
3232
3233                         if (size_ins)
3234                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3235                         else
3236                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3237                         return;
3238                 }
3239         }
3240
3241         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3242                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3243                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3244         } else {
3245                 iargs [0] = dest;
3246                 iargs [1] = src;
3247                 if (size_ins)
3248                         iargs [2] = size_ins;
3249                 else
3250                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3251                 
3252                 memcpy_method = get_memcpy_method ();
3253                 if (memcpy_ins)
3254                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3255                 else
3256                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3257         }
3258 }
3259
3260 static MonoMethod*
3261 get_memset_method (void)
3262 {
3263         static MonoMethod *memset_method = NULL;
3264         if (!memset_method) {
3265                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3266                 if (!memset_method)
3267                         g_error ("Old corlib found. Install a new one");
3268         }
3269         return memset_method;
3270 }
3271
3272 void
3273 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3274 {
3275         MonoInst *iargs [3];
3276         int n, context_used;
3277         guint32 align;
3278         MonoMethod *memset_method;
3279         MonoInst *size_ins = NULL;
3280         MonoInst *bzero_ins = NULL;
3281         static MonoMethod *bzero_method;
3282
3283         /* FIXME: Optimize this for the case when dest is an LDADDR */
3284
3285         mono_class_init (klass);
3286         if (mini_is_gsharedvt_klass (cfg, klass)) {
3287                 context_used = mini_class_check_context_used (cfg, klass);
3288                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3289                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3290                 if (!bzero_method)
3291                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3292                 g_assert (bzero_method);
3293                 iargs [0] = dest;
3294                 iargs [1] = size_ins;
3295                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3296                 return;
3297         }
3298
3299         n = mono_class_value_size (klass, &align);
3300
3301         if (n <= sizeof (gpointer) * 5) {
3302                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3303         }
3304         else {
3305                 memset_method = get_memset_method ();
3306                 iargs [0] = dest;
3307                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3308                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3309                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3310         }
3311 }
3312
3313 static MonoInst*
3314 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3315 {
3316         MonoInst *this = NULL;
3317
3318         g_assert (cfg->generic_sharing_context);
3319
3320         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3321                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3322                         !method->klass->valuetype)
3323                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3324
3325         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3326                 MonoInst *mrgctx_loc, *mrgctx_var;
3327
3328                 g_assert (!this);
3329                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3330
3331                 mrgctx_loc = mono_get_vtable_var (cfg);
3332                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3333
3334                 return mrgctx_var;
3335         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3336                 MonoInst *vtable_loc, *vtable_var;
3337
3338                 g_assert (!this);
3339
3340                 vtable_loc = mono_get_vtable_var (cfg);
3341                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3342
3343                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3344                         MonoInst *mrgctx_var = vtable_var;
3345                         int vtable_reg;
3346
3347                         vtable_reg = alloc_preg (cfg);
3348                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3349                         vtable_var->type = STACK_PTR;
3350                 }
3351
3352                 return vtable_var;
3353         } else {
3354                 MonoInst *ins;
3355                 int vtable_reg;
3356         
3357                 vtable_reg = alloc_preg (cfg);
3358                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3359                 return ins;
3360         }
3361 }
3362
3363 static MonoJumpInfoRgctxEntry *
3364 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3365 {
3366         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3367         res->method = method;
3368         res->in_mrgctx = in_mrgctx;
3369         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3370         res->data->type = patch_type;
3371         res->data->data.target = patch_data;
3372         res->info_type = info_type;
3373
3374         return res;
3375 }
3376
3377 static inline MonoInst*
3378 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3379 {
3380         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3381 }
3382
3383 static MonoInst*
3384 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3385                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3386 {
3387         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);
3388         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3389
3390         return emit_rgctx_fetch (cfg, rgctx, entry);
3391 }
3392
3393 static MonoInst*
3394 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3395                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3396 {
3397         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);
3398         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3399
3400         return emit_rgctx_fetch (cfg, rgctx, entry);
3401 }
3402
3403 static MonoInst*
3404 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3405                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3406 {
3407         MonoJumpInfoGSharedVtCall *call_info;
3408         MonoJumpInfoRgctxEntry *entry;
3409         MonoInst *rgctx;
3410
3411         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3412         call_info->sig = sig;
3413         call_info->method = cmethod;
3414
3415         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);
3416         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3417
3418         return emit_rgctx_fetch (cfg, rgctx, entry);
3419 }
3420
3421
3422 static MonoInst*
3423 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3424                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3425 {
3426         MonoJumpInfoRgctxEntry *entry;
3427         MonoInst *rgctx;
3428
3429         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);
3430         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3431
3432         return emit_rgctx_fetch (cfg, rgctx, entry);
3433 }
3434
3435 /*
3436  * emit_get_rgctx_method:
3437  *
3438  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3439  * normal constants, else emit a load from the rgctx.
3440  */
3441 static MonoInst*
3442 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3443                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3444 {
3445         if (!context_used) {
3446                 MonoInst *ins;
3447
3448                 switch (rgctx_type) {
3449                 case MONO_RGCTX_INFO_METHOD:
3450                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3451                         return ins;
3452                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3453                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3454                         return ins;
3455                 default:
3456                         g_assert_not_reached ();
3457                 }
3458         } else {
3459                 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);
3460                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3461
3462                 return emit_rgctx_fetch (cfg, rgctx, entry);
3463         }
3464 }
3465
3466 static MonoInst*
3467 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3468                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3469 {
3470         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);
3471         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3472
3473         return emit_rgctx_fetch (cfg, rgctx, entry);
3474 }
3475
3476 static int
3477 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3478 {
3479         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3480         MonoRuntimeGenericContextInfoTemplate *template;
3481         int i, idx;
3482
3483         g_assert (info);
3484
3485         for (i = 0; i < info->num_entries; ++i) {
3486                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3487
3488                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3489                         return i;
3490         }
3491
3492         if (info->num_entries == info->count_entries) {
3493                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3494                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3495
3496                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3497
3498                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3499                 info->entries = new_entries;
3500                 info->count_entries = new_count_entries;
3501         }
3502
3503         idx = info->num_entries;
3504         template = &info->entries [idx];
3505         template->info_type = rgctx_type;
3506         template->data = data;
3507
3508         info->num_entries ++;
3509
3510         return idx;
3511 }
3512
3513 /*
3514  * emit_get_gsharedvt_info:
3515  *
3516  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3517  */
3518 static MonoInst*
3519 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3520 {
3521         MonoInst *ins;
3522         int idx, dreg;
3523
3524         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3525         /* Load info->entries [idx] */
3526         dreg = alloc_preg (cfg);
3527         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3528
3529         return ins;
3530 }
3531
3532 static MonoInst*
3533 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3534 {
3535         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3536 }
3537
3538 /*
3539  * On return the caller must check @klass for load errors.
3540  */
3541 static void
3542 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3543 {
3544         MonoInst *vtable_arg;
3545         MonoCallInst *call;
3546         int context_used;
3547
3548         context_used = mini_class_check_context_used (cfg, klass);
3549
3550         if (context_used) {
3551                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3552                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3553         } else {
3554                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3555
3556                 if (!vtable)
3557                         return;
3558                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3559         }
3560
3561         if (COMPILE_LLVM (cfg))
3562                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3563         else
3564                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3565 #ifdef MONO_ARCH_VTABLE_REG
3566         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3567         cfg->uses_vtable_reg = TRUE;
3568 #else
3569         NOT_IMPLEMENTED;
3570 #endif
3571 }
3572
3573 static void
3574 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3575 {
3576         MonoInst *ins;
3577
3578         if (cfg->gen_seq_points && cfg->method == method) {
3579                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3580                 if (nonempty_stack)
3581                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3582                 MONO_ADD_INS (cfg->cbb, ins);
3583         }
3584 }
3585
3586 static void
3587 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3588 {
3589         if (mini_get_debug_options ()->better_cast_details) {
3590                 int to_klass_reg = alloc_preg (cfg);
3591                 int vtable_reg = alloc_preg (cfg);
3592                 int klass_reg = alloc_preg (cfg);
3593                 MonoBasicBlock *is_null_bb = NULL;
3594                 MonoInst *tls_get;
3595
3596                 if (null_check) {
3597                         NEW_BBLOCK (cfg, is_null_bb);
3598
3599                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3600                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3601                 }
3602
3603                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3604                 if (!tls_get) {
3605                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3606                         exit (1);
3607                 }
3608
3609                 MONO_ADD_INS (cfg->cbb, tls_get);
3610                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3611                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3612
3613                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3614                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3615                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3616
3617                 if (null_check) {
3618                         MONO_START_BB (cfg, is_null_bb);
3619                         if (out_bblock)
3620                                 *out_bblock = cfg->cbb;
3621                 }
3622         }
3623 }
3624
3625 static void
3626 reset_cast_details (MonoCompile *cfg)
3627 {
3628         /* Reset the variables holding the cast details */
3629         if (mini_get_debug_options ()->better_cast_details) {
3630                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3631
3632                 MONO_ADD_INS (cfg->cbb, tls_get);
3633                 /* It is enough to reset the from field */
3634                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3635         }
3636 }
3637
3638 /*
3639  * On return the caller must check @array_class for load errors
3640  */
3641 static void
3642 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3643 {
3644         int vtable_reg = alloc_preg (cfg);
3645         int context_used;
3646
3647         context_used = mini_class_check_context_used (cfg, array_class);
3648
3649         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3650
3651         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3652
3653         if (cfg->opt & MONO_OPT_SHARED) {
3654                 int class_reg = alloc_preg (cfg);
3655                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3656                 if (cfg->compile_aot) {
3657                         int klass_reg = alloc_preg (cfg);
3658                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3659                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3660                 } else {
3661                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3662                 }
3663         } else if (context_used) {
3664                 MonoInst *vtable_ins;
3665
3666                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3667                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3668         } else {
3669                 if (cfg->compile_aot) {
3670                         int vt_reg;
3671                         MonoVTable *vtable;
3672
3673                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3674                                 return;
3675                         vt_reg = alloc_preg (cfg);
3676                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3677                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3678                 } else {
3679                         MonoVTable *vtable;
3680                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3681                                 return;
3682                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3683                 }
3684         }
3685         
3686         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3687
3688         reset_cast_details (cfg);
3689 }
3690
3691 /**
3692  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3693  * generic code is generated.
3694  */
3695 static MonoInst*
3696 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3697 {
3698         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3699
3700         if (context_used) {
3701                 MonoInst *rgctx, *addr;
3702
3703                 /* FIXME: What if the class is shared?  We might not
3704                    have to get the address of the method from the
3705                    RGCTX. */
3706                 addr = emit_get_rgctx_method (cfg, context_used, method,
3707                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3708
3709                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3710
3711                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3712         } else {
3713                 gboolean pass_vtable, pass_mrgctx;
3714                 MonoInst *rgctx_arg = NULL;
3715
3716                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3717                 g_assert (!pass_mrgctx);
3718
3719                 if (pass_vtable) {
3720                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3721
3722                         g_assert (vtable);
3723                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3724                 }
3725
3726                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3727         }
3728 }
3729
3730 static MonoInst*
3731 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3732 {
3733         MonoInst *add;
3734         int obj_reg;
3735         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3736         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3737         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3738         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3739
3740         obj_reg = sp [0]->dreg;
3741         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3742         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3743
3744         /* FIXME: generics */
3745         g_assert (klass->rank == 0);
3746                         
3747         // Check rank == 0
3748         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3749         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3750
3751         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3752         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3753
3754         if (context_used) {
3755                 MonoInst *element_class;
3756
3757                 /* This assertion is from the unboxcast insn */
3758                 g_assert (klass->rank == 0);
3759
3760                 element_class = emit_get_rgctx_klass (cfg, context_used,
3761                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3762
3763                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3764                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3765         } else {
3766                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3767                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3768                 reset_cast_details (cfg);
3769         }
3770
3771         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3772         MONO_ADD_INS (cfg->cbb, add);
3773         add->type = STACK_MP;
3774         add->klass = klass;
3775
3776         return add;
3777 }
3778
3779 static MonoInst*
3780 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3781 {
3782         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3783         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3784         MonoInst *ins;
3785         int dreg, addr_reg;
3786
3787         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3788
3789         /* obj */
3790         args [0] = obj;
3791
3792         /* klass */
3793         args [1] = klass_inst;
3794
3795         /* CASTCLASS */
3796         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3797
3798         NEW_BBLOCK (cfg, is_ref_bb);
3799         NEW_BBLOCK (cfg, is_nullable_bb);
3800         NEW_BBLOCK (cfg, end_bb);
3801         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3802         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3803         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3804
3805         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3806         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3807
3808         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3809         addr_reg = alloc_dreg (cfg, STACK_MP);
3810
3811         /* Non-ref case */
3812         /* UNBOX */
3813         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3814         MONO_ADD_INS (cfg->cbb, addr);
3815
3816         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3817
3818         /* Ref case */
3819         MONO_START_BB (cfg, is_ref_bb);
3820
3821         /* Save the ref to a temporary */
3822         dreg = alloc_ireg (cfg);
3823         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3824         addr->dreg = addr_reg;
3825         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3826         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3827
3828         /* Nullable case */
3829         MONO_START_BB (cfg, is_nullable_bb);
3830
3831         {
3832                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3833                 MonoInst *unbox_call;
3834                 MonoMethodSignature *unbox_sig;
3835                 MonoInst *var;
3836
3837                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3838
3839                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3840                 unbox_sig->ret = &klass->byval_arg;
3841                 unbox_sig->param_count = 1;
3842                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3843                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3844
3845                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3846                 addr->dreg = addr_reg;
3847         }
3848
3849         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3850
3851         /* End */
3852         MONO_START_BB (cfg, end_bb);
3853
3854         /* LDOBJ */
3855         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3856
3857         *out_cbb = cfg->cbb;
3858
3859         return ins;
3860 }
3861
3862 /*
3863  * Returns NULL and set the cfg exception on error.
3864  */
3865 static MonoInst*
3866 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3867 {
3868         MonoInst *iargs [2];
3869         void *alloc_ftn;
3870
3871         if (context_used) {
3872                 MonoInst *data;
3873                 int rgctx_info;
3874                 MonoInst *iargs [2];
3875
3876                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3877
3878                 if (cfg->opt & MONO_OPT_SHARED)
3879                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3880                 else
3881                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3882                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3883
3884                 if (cfg->opt & MONO_OPT_SHARED) {
3885                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3886                         iargs [1] = data;
3887                         alloc_ftn = mono_object_new;
3888                 } else {
3889                         iargs [0] = data;
3890                         alloc_ftn = mono_object_new_specific;
3891                 }
3892
3893                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3894                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3895
3896                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3897         }
3898
3899         if (cfg->opt & MONO_OPT_SHARED) {
3900                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3901                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3902
3903                 alloc_ftn = mono_object_new;
3904         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3905                 /* This happens often in argument checking code, eg. throw new FooException... */
3906                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3907                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3908                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3909         } else {
3910                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3911                 MonoMethod *managed_alloc = NULL;
3912                 gboolean pass_lw;
3913
3914                 if (!vtable) {
3915                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3916                         cfg->exception_ptr = klass;
3917                         return NULL;
3918                 }
3919
3920 #ifndef MONO_CROSS_COMPILE
3921                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3922 #endif
3923
3924                 if (managed_alloc) {
3925                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3926                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3927                 }
3928                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3929                 if (pass_lw) {
3930                         guint32 lw = vtable->klass->instance_size;
3931                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3932                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3933                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3934                 }
3935                 else {
3936                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3937                 }
3938         }
3939
3940         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3941 }
3942         
3943 /*
3944  * Returns NULL and set the cfg exception on error.
3945  */     
3946 static MonoInst*
3947 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3948 {
3949         MonoInst *alloc, *ins;
3950
3951         *out_cbb = cfg->cbb;
3952
3953         if (mono_class_is_nullable (klass)) {
3954                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3955
3956                 if (context_used) {
3957                         /* FIXME: What if the class is shared?  We might not
3958                            have to get the method address from the RGCTX. */
3959                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3960                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3961                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3962
3963                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3964                 } else {
3965                         gboolean pass_vtable, pass_mrgctx;
3966                         MonoInst *rgctx_arg = NULL;
3967
3968                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3969                         g_assert (!pass_mrgctx);
3970
3971                         if (pass_vtable) {
3972                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3973
3974                                 g_assert (vtable);
3975                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3976                         }
3977
3978                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3979                 }
3980         }
3981
3982         if (mini_is_gsharedvt_klass (cfg, klass)) {
3983                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3984                 MonoInst *res, *is_ref, *src_var, *addr;
3985                 int addr_reg, dreg;
3986
3987                 dreg = alloc_ireg (cfg);
3988
3989                 NEW_BBLOCK (cfg, is_ref_bb);
3990                 NEW_BBLOCK (cfg, is_nullable_bb);
3991                 NEW_BBLOCK (cfg, end_bb);
3992                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3993                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3994                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3995
3996                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3997                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3998
3999                 /* Non-ref case */
4000                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4001                 if (!alloc)
4002                         return NULL;
4003                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4004                 ins->opcode = OP_STOREV_MEMBASE;
4005
4006                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4007                 res->type = STACK_OBJ;
4008                 res->klass = klass;
4009                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4010                 
4011                 /* Ref case */
4012                 MONO_START_BB (cfg, is_ref_bb);
4013                 addr_reg = alloc_ireg (cfg);
4014
4015                 /* val is a vtype, so has to load the value manually */
4016                 src_var = get_vreg_to_inst (cfg, val->dreg);
4017                 if (!src_var)
4018                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4019                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4020                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4021                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4022
4023                 /* Nullable case */
4024                 MONO_START_BB (cfg, is_nullable_bb);
4025
4026                 {
4027                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4028                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4029                         MonoInst *box_call;
4030                         MonoMethodSignature *box_sig;
4031
4032                         /*
4033                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4034                          * construct that method at JIT time, so have to do things by hand.
4035                          */
4036                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4037                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4038                         box_sig->param_count = 1;
4039                         box_sig->params [0] = &klass->byval_arg;
4040                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4041                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4042                         res->type = STACK_OBJ;
4043                         res->klass = klass;
4044                 }
4045
4046                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4047
4048                 MONO_START_BB (cfg, end_bb);
4049
4050                 *out_cbb = cfg->cbb;
4051
4052                 return res;
4053         } else {
4054                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4055                 if (!alloc)
4056                         return NULL;
4057
4058                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4059                 return alloc;
4060         }
4061 }
4062
4063
4064 static gboolean
4065 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4066 {
4067         int i;
4068         MonoGenericContainer *container;
4069         MonoGenericInst *ginst;
4070
4071         if (klass->generic_class) {
4072                 container = klass->generic_class->container_class->generic_container;
4073                 ginst = klass->generic_class->context.class_inst;
4074         } else if (klass->generic_container && context_used) {
4075                 container = klass->generic_container;
4076                 ginst = container->context.class_inst;
4077         } else {
4078                 return FALSE;
4079         }
4080
4081         for (i = 0; i < container->type_argc; ++i) {
4082                 MonoType *type;
4083                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4084                         continue;
4085                 type = ginst->type_argv [i];
4086                 if (mini_type_is_reference (cfg, type))
4087                         return TRUE;
4088         }
4089         return FALSE;
4090 }
4091
4092 // FIXME: This doesn't work yet (class libs tests fail?)
4093 #define is_complex_isinst(klass) (TRUE || (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)
4094
4095 static MonoInst*
4096 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4097 {
4098         MonoMethod *mono_castclass;
4099         MonoInst *res;
4100
4101         mono_castclass = mono_marshal_get_castclass_with_cache ();
4102
4103         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4104         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4105         reset_cast_details (cfg);
4106
4107         return res;
4108 }
4109
4110 static MonoInst*
4111 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock)
4112 {
4113         MonoInst *args [3];
4114         int idx;
4115
4116         /* obj */
4117         args [0] = obj;
4118
4119         /* klass */
4120         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4121
4122         /* inline cache*/
4123         if (cfg->compile_aot) {
4124                 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4125                 cfg->castclass_cache_index ++;
4126                 idx = (cfg->method_index << 16) | cfg->castclass_cache_index;
4127                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4128         } else {
4129                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4130         }
4131
4132         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4133
4134         return emit_castclass_with_cache (cfg, klass, args, out_bblock);
4135 }
4136
4137 /*
4138  * Returns NULL and set the cfg exception on error.
4139  */
4140 static MonoInst*
4141 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4142 {
4143         MonoBasicBlock *is_null_bb;
4144         int obj_reg = src->dreg;
4145         int vtable_reg = alloc_preg (cfg);
4146         MonoInst *klass_inst = NULL;
4147
4148         if (context_used) {
4149                 MonoInst *args [3];
4150
4151                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4152                         MonoInst *cache_ins;
4153
4154                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4155
4156                         /* obj */
4157                         args [0] = src;
4158
4159                         /* klass - it's the second element of the cache entry*/
4160                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4161
4162                         /* cache */
4163                         args [2] = cache_ins;
4164
4165                         return emit_castclass_with_cache (cfg, klass, args, NULL);
4166                 }
4167
4168                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4169         }
4170
4171         NEW_BBLOCK (cfg, is_null_bb);
4172
4173         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4174         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4175
4176         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4177
4178         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4179                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4180                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4181         } else {
4182                 int klass_reg = alloc_preg (cfg);
4183
4184                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4185
4186                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4187                         /* the remoting code is broken, access the class for now */
4188                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4189                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4190                                 if (!vt) {
4191                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4192                                         cfg->exception_ptr = klass;
4193                                         return NULL;
4194                                 }
4195                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4196                         } else {
4197                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4198                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4199                         }
4200                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4201                 } else {
4202                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4203                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4204                 }
4205         }
4206
4207         MONO_START_BB (cfg, is_null_bb);
4208
4209         reset_cast_details (cfg);
4210
4211         return src;
4212 }
4213
4214 /*
4215  * Returns NULL and set the cfg exception on error.
4216  */
4217 static MonoInst*
4218 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4219 {
4220         MonoInst *ins;
4221         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4222         int obj_reg = src->dreg;
4223         int vtable_reg = alloc_preg (cfg);
4224         int res_reg = alloc_ireg_ref (cfg);
4225         MonoInst *klass_inst = NULL;
4226
4227         if (context_used) {
4228                 MonoInst *args [3];
4229
4230                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4231                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4232                         MonoInst *cache_ins;
4233
4234                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4235
4236                         /* obj */
4237                         args [0] = src;
4238
4239                         /* klass - it's the second element of the cache entry*/
4240                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4241
4242                         /* cache */
4243                         args [2] = cache_ins;
4244
4245                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4246                 }
4247
4248                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4249         }
4250
4251         NEW_BBLOCK (cfg, is_null_bb);
4252         NEW_BBLOCK (cfg, false_bb);
4253         NEW_BBLOCK (cfg, end_bb);
4254
4255         /* Do the assignment at the beginning, so the other assignment can be if converted */
4256         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4257         ins->type = STACK_OBJ;
4258         ins->klass = klass;
4259
4260         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4261         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4262
4263         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4264
4265         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4266                 g_assert (!context_used);
4267                 /* the is_null_bb target simply copies the input register to the output */
4268                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4269         } else {
4270                 int klass_reg = alloc_preg (cfg);
4271
4272                 if (klass->rank) {
4273                         int rank_reg = alloc_preg (cfg);
4274                         int eclass_reg = alloc_preg (cfg);
4275
4276                         g_assert (!context_used);
4277                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4278                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4279                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4280                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4281                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4282                         if (klass->cast_class == mono_defaults.object_class) {
4283                                 int parent_reg = alloc_preg (cfg);
4284                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4285                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4286                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4287                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4288                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4289                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4290                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4291                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4292                         } else if (klass->cast_class == mono_defaults.enum_class) {
4293                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4294                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4295                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4296                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4297                         } else {
4298                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4299                                         /* Check that the object is a vector too */
4300                                         int bounds_reg = alloc_preg (cfg);
4301                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4302                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4303                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4304                                 }
4305
4306                                 /* the is_null_bb target simply copies the input register to the output */
4307                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4308                         }
4309                 } else if (mono_class_is_nullable (klass)) {
4310                         g_assert (!context_used);
4311                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4312                         /* the is_null_bb target simply copies the input register to the output */
4313                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4314                 } else {
4315                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4316                                 g_assert (!context_used);
4317                                 /* the remoting code is broken, access the class for now */
4318                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4319                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4320                                         if (!vt) {
4321                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4322                                                 cfg->exception_ptr = klass;
4323                                                 return NULL;
4324                                         }
4325                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4326                                 } else {
4327                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4328                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4329                                 }
4330                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4331                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4332                         } else {
4333                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4334                                 /* the is_null_bb target simply copies the input register to the output */
4335                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4336                         }
4337                 }
4338         }
4339
4340         MONO_START_BB (cfg, false_bb);
4341
4342         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4343         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4344
4345         MONO_START_BB (cfg, is_null_bb);
4346
4347         MONO_START_BB (cfg, end_bb);
4348
4349         return ins;
4350 }
4351
4352 static MonoInst*
4353 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4354 {
4355         /* This opcode takes as input an object reference and a class, and returns:
4356         0) if the object is an instance of the class,
4357         1) if the object is not instance of the class,
4358         2) if the object is a proxy whose type cannot be determined */
4359
4360         MonoInst *ins;
4361 #ifndef DISABLE_REMOTING
4362         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4363 #else
4364         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4365 #endif
4366         int obj_reg = src->dreg;
4367         int dreg = alloc_ireg (cfg);
4368         int tmp_reg;
4369 #ifndef DISABLE_REMOTING
4370         int klass_reg = alloc_preg (cfg);
4371 #endif
4372
4373         NEW_BBLOCK (cfg, true_bb);
4374         NEW_BBLOCK (cfg, false_bb);
4375         NEW_BBLOCK (cfg, end_bb);
4376 #ifndef DISABLE_REMOTING
4377         NEW_BBLOCK (cfg, false2_bb);
4378         NEW_BBLOCK (cfg, no_proxy_bb);
4379 #endif
4380
4381         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4382         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4383
4384         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4385 #ifndef DISABLE_REMOTING
4386                 NEW_BBLOCK (cfg, interface_fail_bb);
4387 #endif
4388
4389                 tmp_reg = alloc_preg (cfg);
4390                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4391 #ifndef DISABLE_REMOTING
4392                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4393                 MONO_START_BB (cfg, interface_fail_bb);
4394                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4395                 
4396                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4397
4398                 tmp_reg = alloc_preg (cfg);
4399                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4400                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4401                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4402 #else
4403                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4404 #endif
4405         } else {
4406 #ifndef DISABLE_REMOTING
4407                 tmp_reg = alloc_preg (cfg);
4408                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4409                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4410
4411                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4412                 tmp_reg = alloc_preg (cfg);
4413                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4414                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4415
4416                 tmp_reg = alloc_preg (cfg);             
4417                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4418                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4419                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4420                 
4421                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4422                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4423
4424                 MONO_START_BB (cfg, no_proxy_bb);
4425
4426                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4427 #else
4428                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4429 #endif
4430         }
4431
4432         MONO_START_BB (cfg, false_bb);
4433
4434         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4435         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4436
4437 #ifndef DISABLE_REMOTING
4438         MONO_START_BB (cfg, false2_bb);
4439
4440         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4441         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4442 #endif
4443
4444         MONO_START_BB (cfg, true_bb);
4445
4446         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4447
4448         MONO_START_BB (cfg, end_bb);
4449
4450         /* FIXME: */
4451         MONO_INST_NEW (cfg, ins, OP_ICONST);
4452         ins->dreg = dreg;
4453         ins->type = STACK_I4;
4454
4455         return ins;
4456 }
4457
4458 static MonoInst*
4459 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4460 {
4461         /* This opcode takes as input an object reference and a class, and returns:
4462         0) if the object is an instance of the class,
4463         1) if the object is a proxy whose type cannot be determined
4464         an InvalidCastException exception is thrown otherwhise*/
4465         
4466         MonoInst *ins;
4467 #ifndef DISABLE_REMOTING
4468         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4469 #else
4470         MonoBasicBlock *ok_result_bb;
4471 #endif
4472         int obj_reg = src->dreg;
4473         int dreg = alloc_ireg (cfg);
4474         int tmp_reg = alloc_preg (cfg);
4475
4476 #ifndef DISABLE_REMOTING
4477         int klass_reg = alloc_preg (cfg);
4478         NEW_BBLOCK (cfg, end_bb);
4479 #endif
4480
4481         NEW_BBLOCK (cfg, ok_result_bb);
4482
4483         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4484         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4485
4486         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4487
4488         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4489 #ifndef DISABLE_REMOTING
4490                 NEW_BBLOCK (cfg, interface_fail_bb);
4491         
4492                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4493                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4494                 MONO_START_BB (cfg, interface_fail_bb);
4495                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4496
4497                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4498
4499                 tmp_reg = alloc_preg (cfg);             
4500                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4501                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4502                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4503                 
4504                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4505                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4506 #else
4507                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4508                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4509                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4510 #endif
4511         } else {
4512 #ifndef DISABLE_REMOTING
4513                 NEW_BBLOCK (cfg, no_proxy_bb);
4514
4515                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4516                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4517                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4518
4519                 tmp_reg = alloc_preg (cfg);
4520                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4521                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4522
4523                 tmp_reg = alloc_preg (cfg);
4524                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4525                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4526                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4527
4528                 NEW_BBLOCK (cfg, fail_1_bb);
4529                 
4530                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4531
4532                 MONO_START_BB (cfg, fail_1_bb);
4533
4534                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4535                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4536
4537                 MONO_START_BB (cfg, no_proxy_bb);
4538
4539                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4540 #else
4541                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4542 #endif
4543         }
4544
4545         MONO_START_BB (cfg, ok_result_bb);
4546
4547         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4548
4549 #ifndef DISABLE_REMOTING
4550         MONO_START_BB (cfg, end_bb);
4551 #endif
4552
4553         /* FIXME: */
4554         MONO_INST_NEW (cfg, ins, OP_ICONST);
4555         ins->dreg = dreg;
4556         ins->type = STACK_I4;
4557
4558         return ins;
4559 }
4560
4561 /*
4562  * Returns NULL and set the cfg exception on error.
4563  */
4564 static G_GNUC_UNUSED MonoInst*
4565 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4566 {
4567         MonoInst *ptr;
4568         int dreg;
4569         gpointer trampoline;
4570         MonoInst *obj, *method_ins, *tramp_ins;
4571         MonoDomain *domain;
4572         guint8 **code_slot;
4573         
4574         // FIXME reenable optimisation for virtual case
4575         if (virtual)
4576                 return NULL;
4577
4578         if (virtual) {
4579                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4580                 g_assert (invoke);
4581
4582                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4583                         return NULL;
4584         }
4585
4586         obj = handle_alloc (cfg, klass, FALSE, 0);
4587         if (!obj)
4588                 return NULL;
4589
4590         /* Inline the contents of mono_delegate_ctor */
4591
4592         /* Set target field */
4593         /* Optimize away setting of NULL target */
4594         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4595                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4596                 if (cfg->gen_write_barriers) {
4597                         dreg = alloc_preg (cfg);
4598                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4599                         emit_write_barrier (cfg, ptr, target);
4600                 }
4601         }
4602
4603         /* Set method field */
4604         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4605         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4606
4607         /* 
4608          * To avoid looking up the compiled code belonging to the target method
4609          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4610          * store it, and we fill it after the method has been compiled.
4611          */
4612         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4613                 MonoInst *code_slot_ins;
4614
4615                 if (context_used) {
4616                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4617                 } else {
4618                         domain = mono_domain_get ();
4619                         mono_domain_lock (domain);
4620                         if (!domain_jit_info (domain)->method_code_hash)
4621                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4622                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4623                         if (!code_slot) {
4624                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4625                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4626                         }
4627                         mono_domain_unlock (domain);
4628
4629                         if (cfg->compile_aot)
4630                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4631                         else
4632                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4633                 }
4634                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4635         }
4636
4637         if (cfg->compile_aot) {
4638                 MonoDelegateClassMethodPair *del_tramp;
4639
4640                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4641                 del_tramp->klass = klass;
4642                 del_tramp->method = context_used ? NULL : method;
4643                 del_tramp->virtual = virtual;
4644                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4645         } else {
4646                 if (virtual)
4647                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4648                 else
4649                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4650                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4651         }
4652
4653         /* Set invoke_impl field */
4654         if (virtual) {
4655                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4656         } else {
4657                 dreg = alloc_preg (cfg);
4658                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4659                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4660
4661                 dreg = alloc_preg (cfg);
4662                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4663                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4664         }
4665
4666         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4667
4668         return obj;
4669 }
4670
4671 static MonoInst*
4672 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4673 {
4674         MonoJitICallInfo *info;
4675
4676         /* Need to register the icall so it gets an icall wrapper */
4677         info = mono_get_array_new_va_icall (rank);
4678
4679         cfg->flags |= MONO_CFG_HAS_VARARGS;
4680
4681         /* mono_array_new_va () needs a vararg calling convention */
4682         cfg->disable_llvm = TRUE;
4683
4684         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4685         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4686 }
4687
4688 static void
4689 mono_emit_load_got_addr (MonoCompile *cfg)
4690 {
4691         MonoInst *getaddr, *dummy_use;
4692
4693         if (!cfg->got_var || cfg->got_var_allocated)
4694                 return;
4695
4696         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4697         getaddr->cil_code = cfg->header->code;
4698         getaddr->dreg = cfg->got_var->dreg;
4699
4700         /* Add it to the start of the first bblock */
4701         if (cfg->bb_entry->code) {
4702                 getaddr->next = cfg->bb_entry->code;
4703                 cfg->bb_entry->code = getaddr;
4704         }
4705         else
4706                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4707
4708         cfg->got_var_allocated = TRUE;
4709
4710         /* 
4711          * Add a dummy use to keep the got_var alive, since real uses might
4712          * only be generated by the back ends.
4713          * Add it to end_bblock, so the variable's lifetime covers the whole
4714          * method.
4715          * It would be better to make the usage of the got var explicit in all
4716          * cases when the backend needs it (i.e. calls, throw etc.), so this
4717          * wouldn't be needed.
4718          */
4719         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4720         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4721 }
4722
4723 static int inline_limit;
4724 static gboolean inline_limit_inited;
4725
4726 static gboolean
4727 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4728 {
4729         MonoMethodHeaderSummary header;
4730         MonoVTable *vtable;
4731 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4732         MonoMethodSignature *sig = mono_method_signature (method);
4733         int i;
4734 #endif
4735
4736         if (cfg->disable_inline)
4737                 return FALSE;
4738         if (cfg->generic_sharing_context)
4739                 return FALSE;
4740
4741         if (cfg->inline_depth > 10)
4742                 return FALSE;
4743
4744 #ifdef MONO_ARCH_HAVE_LMF_OPS
4745         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4746                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4747             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4748                 return TRUE;
4749 #endif
4750
4751
4752         if (!mono_method_get_header_summary (method, &header))
4753                 return FALSE;
4754
4755         /*runtime, icall and pinvoke are checked by summary call*/
4756         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4757             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4758             (mono_class_is_marshalbyref (method->klass)) ||
4759             header.has_clauses)
4760                 return FALSE;
4761
4762         /* also consider num_locals? */
4763         /* Do the size check early to avoid creating vtables */
4764         if (!inline_limit_inited) {
4765                 if (g_getenv ("MONO_INLINELIMIT"))
4766                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4767                 else
4768                         inline_limit = INLINE_LENGTH_LIMIT;
4769                 inline_limit_inited = TRUE;
4770         }
4771         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4772                 return FALSE;
4773
4774         /*
4775          * if we can initialize the class of the method right away, we do,
4776          * otherwise we don't allow inlining if the class needs initialization,
4777          * since it would mean inserting a call to mono_runtime_class_init()
4778          * inside the inlined code
4779          */
4780         if (!(cfg->opt & MONO_OPT_SHARED)) {
4781                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4782                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4783                         vtable = mono_class_vtable (cfg->domain, method->klass);
4784                         if (!vtable)
4785                                 return FALSE;
4786                         if (!cfg->compile_aot)
4787                                 mono_runtime_class_init (vtable);
4788                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4789                         if (cfg->run_cctors && method->klass->has_cctor) {
4790                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4791                                 if (!method->klass->runtime_info)
4792                                         /* No vtable created yet */
4793                                         return FALSE;
4794                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4795                                 if (!vtable)
4796                                         return FALSE;
4797                                 /* This makes so that inline cannot trigger */
4798                                 /* .cctors: too many apps depend on them */
4799                                 /* running with a specific order... */
4800                                 if (! vtable->initialized)
4801                                         return FALSE;
4802                                 mono_runtime_class_init (vtable);
4803                         }
4804                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4805                         if (!method->klass->runtime_info)
4806                                 /* No vtable created yet */
4807                                 return FALSE;
4808                         vtable = mono_class_vtable (cfg->domain, method->klass);
4809                         if (!vtable)
4810                                 return FALSE;
4811                         if (!vtable->initialized)
4812                                 return FALSE;
4813                 }
4814         } else {
4815                 /* 
4816                  * If we're compiling for shared code
4817                  * the cctor will need to be run at aot method load time, for example,
4818                  * or at the end of the compilation of the inlining method.
4819                  */
4820                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4821                         return FALSE;
4822         }
4823
4824         /*
4825          * CAS - do not inline methods with declarative security
4826          * Note: this has to be before any possible return TRUE;
4827          */
4828         if (mono_security_method_has_declsec (method))
4829                 return FALSE;
4830
4831 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4832         if (mono_arch_is_soft_float ()) {
4833                 /* FIXME: */
4834                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4835                         return FALSE;
4836                 for (i = 0; i < sig->param_count; ++i)
4837                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4838                                 return FALSE;
4839         }
4840 #endif
4841
4842         if (g_list_find (cfg->dont_inline, method))
4843                 return FALSE;
4844
4845         return TRUE;
4846 }
4847
4848 static gboolean
4849 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4850 {
4851         if (!cfg->compile_aot) {
4852                 g_assert (vtable);
4853                 if (vtable->initialized)
4854                         return FALSE;
4855         }
4856
4857         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4858                 if (cfg->method == method)
4859                         return FALSE;
4860         }
4861
4862         if (!mono_class_needs_cctor_run (klass, method))
4863                 return FALSE;
4864
4865         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4866                 /* The initialization is already done before the method is called */
4867                 return FALSE;
4868
4869         return TRUE;
4870 }
4871
4872 static MonoInst*
4873 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4874 {
4875         MonoInst *ins;
4876         guint32 size;
4877         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4878         int context_used;
4879
4880         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
4881                 size = -1;
4882         } else {
4883                 mono_class_init (klass);
4884                 size = mono_class_array_element_size (klass);
4885         }
4886
4887         mult_reg = alloc_preg (cfg);
4888         array_reg = arr->dreg;
4889         index_reg = index->dreg;
4890
4891 #if SIZEOF_REGISTER == 8
4892         /* The array reg is 64 bits but the index reg is only 32 */
4893         if (COMPILE_LLVM (cfg)) {
4894                 /* Not needed */
4895                 index2_reg = index_reg;
4896         } else {
4897                 index2_reg = alloc_preg (cfg);
4898                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4899         }
4900 #else
4901         if (index->type == STACK_I8) {
4902                 index2_reg = alloc_preg (cfg);
4903                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4904         } else {
4905                 index2_reg = index_reg;
4906         }
4907 #endif
4908
4909         if (bcheck)
4910                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4911
4912 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4913         if (size == 1 || size == 2 || size == 4 || size == 8) {
4914                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4915
4916                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4917                 ins->klass = mono_class_get_element_class (klass);
4918                 ins->type = STACK_MP;
4919
4920                 return ins;
4921         }
4922 #endif          
4923
4924         add_reg = alloc_ireg_mp (cfg);
4925
4926         if (size == -1) {
4927                 MonoInst *rgctx_ins;
4928
4929                 /* gsharedvt */
4930                 g_assert (cfg->generic_sharing_context);
4931                 context_used = mini_class_check_context_used (cfg, klass);
4932                 g_assert (context_used);
4933                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4934                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4935         } else {
4936                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4937         }
4938         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4939         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4940         ins->klass = mono_class_get_element_class (klass);
4941         ins->type = STACK_MP;
4942         MONO_ADD_INS (cfg->cbb, ins);
4943
4944         return ins;
4945 }
4946
4947 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4948 static MonoInst*
4949 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4950 {
4951         int bounds_reg = alloc_preg (cfg);
4952         int add_reg = alloc_ireg_mp (cfg);
4953         int mult_reg = alloc_preg (cfg);
4954         int mult2_reg = alloc_preg (cfg);
4955         int low1_reg = alloc_preg (cfg);
4956         int low2_reg = alloc_preg (cfg);
4957         int high1_reg = alloc_preg (cfg);
4958         int high2_reg = alloc_preg (cfg);
4959         int realidx1_reg = alloc_preg (cfg);
4960         int realidx2_reg = alloc_preg (cfg);
4961         int sum_reg = alloc_preg (cfg);
4962         int index1, index2, tmpreg;
4963         MonoInst *ins;
4964         guint32 size;
4965
4966         mono_class_init (klass);
4967         size = mono_class_array_element_size (klass);
4968
4969         index1 = index_ins1->dreg;
4970         index2 = index_ins2->dreg;
4971
4972 #if SIZEOF_REGISTER == 8
4973         /* The array reg is 64 bits but the index reg is only 32 */
4974         if (COMPILE_LLVM (cfg)) {
4975                 /* Not needed */
4976         } else {
4977                 tmpreg = alloc_preg (cfg);
4978                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4979                 index1 = tmpreg;
4980                 tmpreg = alloc_preg (cfg);
4981                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4982                 index2 = tmpreg;
4983         }
4984 #else
4985         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4986         tmpreg = -1;
4987 #endif
4988
4989         /* range checking */
4990         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4991                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4992
4993         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4994                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4995         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4996         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4997                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
4998         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4999         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5000
5001         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5002                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5003         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5004         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5005                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5006         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5007         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5008
5009         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5010         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5011         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5012         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5013         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5014
5015         ins->type = STACK_MP;
5016         ins->klass = klass;
5017         MONO_ADD_INS (cfg->cbb, ins);
5018
5019         return ins;
5020 }
5021 #endif
5022
5023 static MonoInst*
5024 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5025 {
5026         int rank;
5027         MonoInst *addr;
5028         MonoMethod *addr_method;
5029         int element_size;
5030
5031         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5032
5033         if (rank == 1)
5034                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
5035
5036 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5037         /* emit_ldelema_2 depends on OP_LMUL */
5038         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
5039                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
5040         }
5041 #endif
5042
5043         element_size = mono_class_array_element_size (cmethod->klass->element_class);
5044         addr_method = mono_marshal_get_array_address (rank, element_size);
5045         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5046
5047         return addr;
5048 }
5049
5050 static MonoBreakPolicy
5051 always_insert_breakpoint (MonoMethod *method)
5052 {
5053         return MONO_BREAK_POLICY_ALWAYS;
5054 }
5055
5056 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5057
5058 /**
5059  * mono_set_break_policy:
5060  * policy_callback: the new callback function
5061  *
5062  * Allow embedders to decide wherther to actually obey breakpoint instructions
5063  * (both break IL instructions and Debugger.Break () method calls), for example
5064  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5065  * untrusted or semi-trusted code.
5066  *
5067  * @policy_callback will be called every time a break point instruction needs to
5068  * be inserted with the method argument being the method that calls Debugger.Break()
5069  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5070  * if it wants the breakpoint to not be effective in the given method.
5071  * #MONO_BREAK_POLICY_ALWAYS is the default.
5072  */
5073 void
5074 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5075 {
5076         if (policy_callback)
5077                 break_policy_func = policy_callback;
5078         else
5079                 break_policy_func = always_insert_breakpoint;
5080 }
5081
5082 static gboolean
5083 should_insert_brekpoint (MonoMethod *method) {
5084         switch (break_policy_func (method)) {
5085         case MONO_BREAK_POLICY_ALWAYS:
5086                 return TRUE;
5087         case MONO_BREAK_POLICY_NEVER:
5088                 return FALSE;
5089         case MONO_BREAK_POLICY_ON_DBG:
5090                 g_warning ("mdb no longer supported");
5091                 return FALSE;
5092         default:
5093                 g_warning ("Incorrect value returned from break policy callback");
5094                 return FALSE;
5095         }
5096 }
5097
5098 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5099 static MonoInst*
5100 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5101 {
5102         MonoInst *addr, *store, *load;
5103         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5104
5105         /* the bounds check is already done by the callers */
5106         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5107         if (is_set) {
5108                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5109                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5110                 if (mini_type_is_reference (cfg, fsig->params [2]))
5111                         emit_write_barrier (cfg, addr, load);
5112         } else {
5113                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5114                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5115         }
5116         return store;
5117 }
5118
5119
5120 static gboolean
5121 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5122 {
5123         return mini_type_is_reference (cfg, &klass->byval_arg);
5124 }
5125
5126 static MonoInst*
5127 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5128 {
5129         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5130                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5131                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5132                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5133                 MonoInst *iargs [3];
5134
5135                 if (!helper->slot)
5136                         mono_class_setup_vtable (obj_array);
5137                 g_assert (helper->slot);
5138
5139                 if (sp [0]->type != STACK_OBJ)
5140                         return NULL;
5141                 if (sp [2]->type != STACK_OBJ)
5142                         return NULL;
5143
5144                 iargs [2] = sp [2];
5145                 iargs [1] = sp [1];
5146                 iargs [0] = sp [0];
5147
5148                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5149         } else {
5150                 MonoInst *ins;
5151
5152                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5153                         MonoInst *addr;
5154
5155                         // FIXME-VT: OP_ICONST optimization
5156                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5157                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5158                         ins->opcode = OP_STOREV_MEMBASE;
5159                 } else if (sp [1]->opcode == OP_ICONST) {
5160                         int array_reg = sp [0]->dreg;
5161                         int index_reg = sp [1]->dreg;
5162                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5163
5164                         if (safety_checks)
5165                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5166                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5167                 } else {
5168                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5169                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5170                         if (generic_class_is_reference_type (cfg, klass))
5171                                 emit_write_barrier (cfg, addr, sp [2]);
5172                 }
5173                 return ins;
5174         }
5175 }
5176
5177 static MonoInst*
5178 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5179 {
5180         MonoClass *eklass;
5181         
5182         if (is_set)
5183                 eklass = mono_class_from_mono_type (fsig->params [2]);
5184         else
5185                 eklass = mono_class_from_mono_type (fsig->ret);
5186
5187         if (is_set) {
5188                 return emit_array_store (cfg, eklass, args, FALSE);
5189         } else {
5190                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5191                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5192                 return ins;
5193         }
5194 }
5195
5196 static gboolean
5197 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5198 {
5199         uint32_t align;
5200
5201         //Only allow for valuetypes
5202         if (!param_klass->valuetype || !return_klass->valuetype)
5203                 return FALSE;
5204
5205         //That are blitable
5206         if (param_klass->has_references || return_klass->has_references)
5207                 return FALSE;
5208
5209         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5210         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5211                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5212                 return FALSE;
5213
5214         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5215                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5216                 return FALSE;
5217
5218         //And have the same size
5219         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5220                 return FALSE;
5221         return TRUE;
5222 }
5223
5224 static MonoInst*
5225 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5226 {
5227         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5228         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5229
5230         //Valuetypes that are semantically equivalent
5231         if (is_unsafe_mov_compatible (param_klass, return_klass))
5232                 return args [0];
5233
5234         //Arrays of valuetypes that are semantically equivalent
5235         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5236                 return args [0];
5237
5238         return NULL;
5239 }
5240
5241 static MonoInst*
5242 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5243 {
5244 #ifdef MONO_ARCH_SIMD_INTRINSICS
5245         MonoInst *ins = NULL;
5246
5247         if (cfg->opt & MONO_OPT_SIMD) {
5248                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5249                 if (ins)
5250                         return ins;
5251         }
5252 #endif
5253
5254         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5255 }
5256
5257 static MonoInst*
5258 emit_memory_barrier (MonoCompile *cfg, int kind)
5259 {
5260         MonoInst *ins = NULL;
5261         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5262         MONO_ADD_INS (cfg->cbb, ins);
5263         ins->backend.memory_barrier_kind = kind;
5264
5265         return ins;
5266 }
5267
5268 static MonoInst*
5269 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5270 {
5271         MonoInst *ins = NULL;
5272         int opcode = 0;
5273
5274         /* The LLVM backend supports these intrinsics */
5275         if (cmethod->klass == mono_defaults.math_class) {
5276                 if (strcmp (cmethod->name, "Sin") == 0) {
5277                         opcode = OP_SIN;
5278                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5279                         opcode = OP_COS;
5280                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5281                         opcode = OP_SQRT;
5282                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5283                         opcode = OP_ABS;
5284                 }
5285
5286                 if (opcode) {
5287                         MONO_INST_NEW (cfg, ins, opcode);
5288                         ins->type = STACK_R8;
5289                         ins->dreg = mono_alloc_freg (cfg);
5290                         ins->sreg1 = args [0]->dreg;
5291                         MONO_ADD_INS (cfg->cbb, ins);
5292                 }
5293
5294                 opcode = 0;
5295                 if (cfg->opt & MONO_OPT_CMOV) {
5296                         if (strcmp (cmethod->name, "Min") == 0) {
5297                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5298                                         opcode = OP_IMIN;
5299                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5300                                         opcode = OP_IMIN_UN;
5301                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5302                                         opcode = OP_LMIN;
5303                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5304                                         opcode = OP_LMIN_UN;
5305                         } else if (strcmp (cmethod->name, "Max") == 0) {
5306                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5307                                         opcode = OP_IMAX;
5308                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5309                                         opcode = OP_IMAX_UN;
5310                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5311                                         opcode = OP_LMAX;
5312                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5313                                         opcode = OP_LMAX_UN;
5314                         }
5315                 }
5316
5317                 if (opcode) {
5318                         MONO_INST_NEW (cfg, ins, opcode);
5319                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5320                         ins->dreg = mono_alloc_ireg (cfg);
5321                         ins->sreg1 = args [0]->dreg;
5322                         ins->sreg2 = args [1]->dreg;
5323                         MONO_ADD_INS (cfg->cbb, ins);
5324                 }
5325         }
5326
5327         return ins;
5328 }
5329
5330 static MonoInst*
5331 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5332 {
5333         if (cmethod->klass == mono_defaults.array_class) {
5334                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5335                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5336                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5337                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5338                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5339                         return emit_array_unsafe_mov (cfg, fsig, args);
5340         }
5341
5342         return NULL;
5343 }
5344
5345 static MonoInst*
5346 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5347 {
5348         MonoInst *ins = NULL;
5349         
5350         static MonoClass *runtime_helpers_class = NULL;
5351         if (! runtime_helpers_class)
5352                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5353                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5354
5355         if (cmethod->klass == mono_defaults.string_class) {
5356                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5357                         int dreg = alloc_ireg (cfg);
5358                         int index_reg = alloc_preg (cfg);
5359                         int mult_reg = alloc_preg (cfg);
5360                         int add_reg = alloc_preg (cfg);
5361
5362 #if SIZEOF_REGISTER == 8
5363                         /* The array reg is 64 bits but the index reg is only 32 */
5364                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5365 #else
5366                         index_reg = args [1]->dreg;
5367 #endif  
5368                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5369
5370 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5371                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5372                         add_reg = ins->dreg;
5373                         /* Avoid a warning */
5374                         mult_reg = 0;
5375                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5376                                                                    add_reg, 0);
5377 #else
5378                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5379                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5380                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5381                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5382 #endif
5383                         type_from_op (ins, NULL, NULL);
5384                         return ins;
5385                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5386                         int dreg = alloc_ireg (cfg);
5387                         /* Decompose later to allow more optimizations */
5388                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5389                         ins->type = STACK_I4;
5390                         ins->flags |= MONO_INST_FAULT;
5391                         cfg->cbb->has_array_access = TRUE;
5392                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5393
5394                         return ins;
5395                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5396                         int mult_reg = alloc_preg (cfg);
5397                         int add_reg = alloc_preg (cfg);
5398
5399                         /* The corlib functions check for oob already. */
5400                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5401                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5402                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, MONO_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5403                         return cfg->cbb->last_ins;
5404                 } else 
5405                         return NULL;
5406         } else if (cmethod->klass == mono_defaults.object_class) {
5407
5408                 if (strcmp (cmethod->name, "GetType") == 0) {
5409                         int dreg = alloc_ireg_ref (cfg);
5410                         int vt_reg = alloc_preg (cfg);
5411                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5412                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5413                         type_from_op (ins, NULL, NULL);
5414
5415                         return ins;
5416 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5417                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5418                         int dreg = alloc_ireg (cfg);
5419                         int t1 = alloc_ireg (cfg);
5420         
5421                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5422                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5423                         ins->type = STACK_I4;
5424
5425                         return ins;
5426 #endif
5427                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5428                         MONO_INST_NEW (cfg, ins, OP_NOP);
5429                         MONO_ADD_INS (cfg->cbb, ins);
5430                         return ins;
5431                 } else
5432                         return NULL;
5433         } else if (cmethod->klass == mono_defaults.array_class) {
5434                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5435                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5436
5437 #ifndef MONO_BIG_ARRAYS
5438                 /*
5439                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5440                  * Array methods.
5441                  */
5442                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5443                         int dreg = alloc_ireg (cfg);
5444                         int bounds_reg = alloc_ireg_mp (cfg);
5445                         MonoBasicBlock *end_bb, *szarray_bb;
5446                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5447
5448                         NEW_BBLOCK (cfg, end_bb);
5449                         NEW_BBLOCK (cfg, szarray_bb);
5450
5451                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5452                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5453                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5454                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5455                         /* Non-szarray case */
5456                         if (get_length)
5457                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5458                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5459                         else
5460                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5461                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5462                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5463                         MONO_START_BB (cfg, szarray_bb);
5464                         /* Szarray case */
5465                         if (get_length)
5466                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5467                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5468                         else
5469                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5470                         MONO_START_BB (cfg, end_bb);
5471
5472                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5473                         ins->type = STACK_I4;
5474                         
5475                         return ins;
5476                 }
5477 #endif
5478
5479                 if (cmethod->name [0] != 'g')
5480                         return NULL;
5481
5482                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5483                         int dreg = alloc_ireg (cfg);
5484                         int vtable_reg = alloc_preg (cfg);
5485                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5486                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5487                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5488                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5489                         type_from_op (ins, NULL, NULL);
5490
5491                         return ins;
5492                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5493                         int dreg = alloc_ireg (cfg);
5494
5495                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5496                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5497                         type_from_op (ins, NULL, NULL);
5498
5499                         return ins;
5500                 } else
5501                         return NULL;
5502         } else if (cmethod->klass == runtime_helpers_class) {
5503
5504                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5505                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5506                         return ins;
5507                 } else
5508                         return NULL;
5509         } else if (cmethod->klass == mono_defaults.thread_class) {
5510                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5511                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5512                         MONO_ADD_INS (cfg->cbb, ins);
5513                         return ins;
5514                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5515                         return emit_memory_barrier (cfg, FullBarrier);
5516                 }
5517         } else if (cmethod->klass == mono_defaults.monitor_class) {
5518
5519                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5520 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5521                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5522                         MonoMethod *fast_method = NULL;
5523
5524                         /* Avoid infinite recursion */
5525                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5526                                 return NULL;
5527                                 
5528                         fast_method = mono_monitor_get_fast_path (cmethod);
5529                         if (!fast_method)
5530                                 return NULL;
5531
5532                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5533                 }
5534 #endif
5535
5536 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5537                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5538                         MonoCallInst *call;
5539
5540                         if (COMPILE_LLVM (cfg)) {
5541                                 /* 
5542                                  * Pass the argument normally, the LLVM backend will handle the
5543                                  * calling convention problems.
5544                                  */
5545                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5546                         } else {
5547                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5548                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5549                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5550                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5551                         }
5552
5553                         return (MonoInst*)call;
5554                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5555                         MonoCallInst *call;
5556
5557                         if (COMPILE_LLVM (cfg)) {
5558                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5559                         } else {
5560                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5561                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5562                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5563                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5564                         }
5565
5566                         return (MonoInst*)call;
5567                 }
5568 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5569                 {
5570                 MonoMethod *fast_method = NULL;
5571
5572                 /* Avoid infinite recursion */
5573                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5574                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5575                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5576                         return NULL;
5577
5578                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5579                                 strcmp (cmethod->name, "Exit") == 0)
5580                         fast_method = mono_monitor_get_fast_path (cmethod);
5581                 if (!fast_method)
5582                         return NULL;
5583
5584                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5585                 }
5586 #endif
5587         } else if (cmethod->klass->image == mono_defaults.corlib &&
5588                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5589                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5590                 ins = NULL;
5591
5592 #if SIZEOF_REGISTER == 8
5593                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5594                         MonoInst *load_ins;
5595
5596                         emit_memory_barrier (cfg, FullBarrier);
5597
5598                         /* 64 bit reads are already atomic */
5599                         MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5600                         load_ins->dreg = mono_alloc_preg (cfg);
5601                         load_ins->inst_basereg = args [0]->dreg;
5602                         load_ins->inst_offset = 0;
5603                         MONO_ADD_INS (cfg->cbb, load_ins);
5604
5605                         emit_memory_barrier (cfg, FullBarrier);
5606
5607                         ins = load_ins;
5608                 }
5609 #endif
5610
5611                 if (strcmp (cmethod->name, "Increment") == 0) {
5612                         MonoInst *ins_iconst;
5613                         guint32 opcode = 0;
5614
5615                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5616                                 opcode = OP_ATOMIC_ADD_I4;
5617                                 cfg->has_atomic_add_i4 = TRUE;
5618                         }
5619 #if SIZEOF_REGISTER == 8
5620                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5621                                 opcode = OP_ATOMIC_ADD_I8;
5622 #endif
5623                         if (opcode) {
5624                                 if (!mono_arch_opcode_supported (opcode))
5625                                         return NULL;
5626                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5627                                 ins_iconst->inst_c0 = 1;
5628                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5629                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5630
5631                                 MONO_INST_NEW (cfg, ins, opcode);
5632                                 ins->dreg = mono_alloc_ireg (cfg);
5633                                 ins->inst_basereg = args [0]->dreg;
5634                                 ins->inst_offset = 0;
5635                                 ins->sreg2 = ins_iconst->dreg;
5636                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5637                                 MONO_ADD_INS (cfg->cbb, ins);
5638                         }
5639                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5640                         MonoInst *ins_iconst;
5641                         guint32 opcode = 0;
5642
5643                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5644                                 opcode = OP_ATOMIC_ADD_I4;
5645                                 cfg->has_atomic_add_i4 = TRUE;
5646                         }
5647 #if SIZEOF_REGISTER == 8
5648                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5649                                 opcode = OP_ATOMIC_ADD_I8;
5650 #endif
5651                         if (opcode) {
5652                                 if (!mono_arch_opcode_supported (opcode))
5653                                         return NULL;
5654                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5655                                 ins_iconst->inst_c0 = -1;
5656                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5657                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5658
5659                                 MONO_INST_NEW (cfg, ins, opcode);
5660                                 ins->dreg = mono_alloc_ireg (cfg);
5661                                 ins->inst_basereg = args [0]->dreg;
5662                                 ins->inst_offset = 0;
5663                                 ins->sreg2 = ins_iconst->dreg;
5664                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5665                                 MONO_ADD_INS (cfg->cbb, ins);
5666                         }
5667                 } else if (strcmp (cmethod->name, "Add") == 0) {
5668                         guint32 opcode = 0;
5669
5670                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5671                                 opcode = OP_ATOMIC_ADD_I4;
5672                                 cfg->has_atomic_add_i4 = TRUE;
5673                         }
5674 #if SIZEOF_REGISTER == 8
5675                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5676                                 opcode = OP_ATOMIC_ADD_I8;
5677 #endif
5678                         if (opcode) {
5679                                 if (!mono_arch_opcode_supported (opcode))
5680                                         return NULL;
5681                                 MONO_INST_NEW (cfg, ins, opcode);
5682                                 ins->dreg = mono_alloc_ireg (cfg);
5683                                 ins->inst_basereg = args [0]->dreg;
5684                                 ins->inst_offset = 0;
5685                                 ins->sreg2 = args [1]->dreg;
5686                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5687                                 MONO_ADD_INS (cfg->cbb, ins);
5688                         }
5689                 }
5690
5691                 if (strcmp (cmethod->name, "Exchange") == 0) {
5692                         guint32 opcode;
5693                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5694
5695                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5696                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5697                                 cfg->has_atomic_exchange_i4 = TRUE;
5698                         }
5699 #if SIZEOF_REGISTER == 8
5700                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5701                                         (fsig->params [0]->type == MONO_TYPE_I))
5702                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5703 #else
5704                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I)) {
5705                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5706                                 cfg->has_atomic_exchange_i4 = TRUE;
5707                         }
5708 #endif
5709                         else
5710                                 return NULL;
5711
5712                         if (!mono_arch_opcode_supported (opcode))
5713                                 return NULL;
5714
5715                         MONO_INST_NEW (cfg, ins, opcode);
5716                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5717                         ins->inst_basereg = args [0]->dreg;
5718                         ins->inst_offset = 0;
5719                         ins->sreg2 = args [1]->dreg;
5720                         MONO_ADD_INS (cfg->cbb, ins);
5721
5722                         switch (fsig->params [0]->type) {
5723                         case MONO_TYPE_I4:
5724                                 ins->type = STACK_I4;
5725                                 break;
5726                         case MONO_TYPE_I8:
5727                         case MONO_TYPE_I:
5728                                 ins->type = STACK_I8;
5729                                 break;
5730                         case MONO_TYPE_OBJECT:
5731                                 ins->type = STACK_OBJ;
5732                                 break;
5733                         default:
5734                                 g_assert_not_reached ();
5735                         }
5736
5737                         if (cfg->gen_write_barriers && is_ref)
5738                                 emit_write_barrier (cfg, args [0], args [1]);
5739                 }
5740
5741                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5742                         int size = 0;
5743                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5744                         if (fsig->params [1]->type == MONO_TYPE_I4)
5745                                 size = 4;
5746                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5747                                 size = sizeof (gpointer);
5748                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5749                                 size = 8;
5750                         if (size == 4) {
5751                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5752                                         return NULL;
5753                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5754                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5755                                 ins->sreg1 = args [0]->dreg;
5756                                 ins->sreg2 = args [1]->dreg;
5757                                 ins->sreg3 = args [2]->dreg;
5758                                 ins->type = STACK_I4;
5759                                 MONO_ADD_INS (cfg->cbb, ins);
5760                                 cfg->has_atomic_cas_i4 = TRUE;
5761                         } else if (size == 8) {
5762                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I8))
5763                                         return NULL;
5764                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5765                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5766                                 ins->sreg1 = args [0]->dreg;
5767                                 ins->sreg2 = args [1]->dreg;
5768                                 ins->sreg3 = args [2]->dreg;
5769                                 ins->type = STACK_I8;
5770                                 MONO_ADD_INS (cfg->cbb, ins);
5771                         } else {
5772                                 /* g_assert_not_reached (); */
5773                         }
5774                         if (cfg->gen_write_barriers && is_ref)
5775                                 emit_write_barrier (cfg, args [0], args [1]);
5776                 }
5777
5778                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5779                         ins = emit_memory_barrier (cfg, FullBarrier);
5780
5781                 if (ins)
5782                         return ins;
5783         } else if (cmethod->klass->image == mono_defaults.corlib) {
5784                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5785                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5786                         if (should_insert_brekpoint (cfg->method)) {
5787                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5788                         } else {
5789                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5790                                 MONO_ADD_INS (cfg->cbb, ins);
5791                         }
5792                         return ins;
5793                 }
5794                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5795                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5796 #ifdef TARGET_WIN32
5797                         EMIT_NEW_ICONST (cfg, ins, 1);
5798 #else
5799                         EMIT_NEW_ICONST (cfg, ins, 0);
5800 #endif
5801                         return ins;
5802                 }
5803         } else if (cmethod->klass == mono_defaults.math_class) {
5804                 /* 
5805                  * There is general branches code for Min/Max, but it does not work for 
5806                  * all inputs:
5807                  * http://everything2.com/?node_id=1051618
5808                  */
5809         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") || !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) && !strcmp (cmethod->klass->name, "Selector") && !strcmp (cmethod->name, "GetHandle") && cfg->compile_aot && (args [0]->opcode == OP_GOT_ENTRY || args[0]->opcode == OP_AOTCONST)) {
5810 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5811                 MonoInst *pi;
5812                 MonoJumpInfoToken *ji;
5813                 MonoString *s;
5814
5815                 cfg->disable_llvm = TRUE;
5816
5817                 if (args [0]->opcode == OP_GOT_ENTRY) {
5818                         pi = args [0]->inst_p1;
5819                         g_assert (pi->opcode == OP_PATCH_INFO);
5820                         g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
5821                         ji = pi->inst_p0;
5822                 } else {
5823                         g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
5824                         ji = args [0]->inst_p0;
5825                 }
5826
5827                 NULLIFY_INS (args [0]);
5828
5829                 // FIXME: Ugly
5830                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5831                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5832                 ins->dreg = mono_alloc_ireg (cfg);
5833                 // FIXME: Leaks
5834                 ins->inst_p0 = mono_string_to_utf8 (s);
5835                 MONO_ADD_INS (cfg->cbb, ins);
5836                 return ins;
5837 #endif
5838         }
5839
5840 #ifdef MONO_ARCH_SIMD_INTRINSICS
5841         if (cfg->opt & MONO_OPT_SIMD) {
5842                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5843                 if (ins)
5844                         return ins;
5845         }
5846 #endif
5847
5848         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5849         if (ins)
5850                 return ins;
5851
5852         if (COMPILE_LLVM (cfg)) {
5853                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5854                 if (ins)
5855                         return ins;
5856         }
5857
5858         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5859 }
5860
5861 /*
5862  * This entry point could be used later for arbitrary method
5863  * redirection.
5864  */
5865 inline static MonoInst*
5866 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5867                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5868 {
5869         if (method->klass == mono_defaults.string_class) {
5870                 /* managed string allocation support */
5871                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5872                         MonoInst *iargs [2];
5873                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5874                         MonoMethod *managed_alloc = NULL;
5875
5876                         g_assert (vtable); /*Should not fail since it System.String*/
5877 #ifndef MONO_CROSS_COMPILE
5878                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5879 #endif
5880                         if (!managed_alloc)
5881                                 return NULL;
5882                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5883                         iargs [1] = args [0];
5884                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5885                 }
5886         }
5887         return NULL;
5888 }
5889
5890 static void
5891 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5892 {
5893         MonoInst *store, *temp;
5894         int i;
5895
5896         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5897                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5898
5899                 /*
5900                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5901                  * would be different than the MonoInst's used to represent arguments, and
5902                  * the ldelema implementation can't deal with that.
5903                  * Solution: When ldelema is used on an inline argument, create a var for 
5904                  * it, emit ldelema on that var, and emit the saving code below in
5905                  * inline_method () if needed.
5906                  */
5907                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5908                 cfg->args [i] = temp;
5909                 /* This uses cfg->args [i] which is set by the preceeding line */
5910                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5911                 store->cil_code = sp [0]->cil_code;
5912                 sp++;
5913         }
5914 }
5915
5916 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5917 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5918
5919 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5920 static gboolean
5921 check_inline_called_method_name_limit (MonoMethod *called_method)
5922 {
5923         int strncmp_result;
5924         static const char *limit = NULL;
5925         
5926         if (limit == NULL) {
5927                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5928
5929                 if (limit_string != NULL)
5930                         limit = limit_string;
5931                 else
5932                         limit = "";
5933         }
5934
5935         if (limit [0] != '\0') {
5936                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5937
5938                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5939                 g_free (called_method_name);
5940         
5941                 //return (strncmp_result <= 0);
5942                 return (strncmp_result == 0);
5943         } else {
5944                 return TRUE;
5945         }
5946 }
5947 #endif
5948
5949 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5950 static gboolean
5951 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5952 {
5953         int strncmp_result;
5954         static const char *limit = NULL;
5955         
5956         if (limit == NULL) {
5957                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5958                 if (limit_string != NULL) {
5959                         limit = limit_string;
5960                 } else {
5961                         limit = "";
5962                 }
5963         }
5964
5965         if (limit [0] != '\0') {
5966                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5967
5968                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5969                 g_free (caller_method_name);
5970         
5971                 //return (strncmp_result <= 0);
5972                 return (strncmp_result == 0);
5973         } else {
5974                 return TRUE;
5975         }
5976 }
5977 #endif
5978
5979 static void
5980 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
5981 {
5982         static double r8_0 = 0.0;
5983         MonoInst *ins;
5984         int t;
5985
5986         rtype = mini_replace_type (rtype);
5987         t = rtype->type;
5988
5989         if (rtype->byref) {
5990                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
5991         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
5992                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5993         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
5994                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
5995         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
5996                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5997                 ins->type = STACK_R8;
5998                 ins->inst_p0 = (void*)&r8_0;
5999                 ins->dreg = dreg;
6000                 MONO_ADD_INS (cfg->cbb, ins);
6001         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6002                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6003                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6004         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6005                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6006         } else {
6007                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6008         }
6009 }
6010
6011 static void
6012 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6013 {
6014         int t;
6015
6016         rtype = mini_replace_type (rtype);
6017         t = rtype->type;
6018
6019         if (rtype->byref) {
6020                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6021         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6022                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6023         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6024                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6025         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6026                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6027         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6028                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6029                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6030         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6031                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6032         } else {
6033                 emit_init_rvar (cfg, dreg, rtype);
6034         }
6035 }
6036
6037 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6038 static void
6039 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6040 {
6041         MonoInst *var = cfg->locals [local];
6042         if (COMPILE_SOFT_FLOAT (cfg)) {
6043                 MonoInst *store;
6044                 int reg = alloc_dreg (cfg, var->type);
6045                 emit_init_rvar (cfg, reg, type);
6046                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6047         } else {
6048                 if (init)
6049                         emit_init_rvar (cfg, var->dreg, type);
6050                 else
6051                         emit_dummy_init_rvar (cfg, var->dreg, type);
6052         }
6053 }
6054
6055 /*
6056  * inline_method:
6057  *
6058  *   Return the cost of inlining CMETHOD.
6059  */
6060 static int
6061 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6062                            guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
6063 {
6064         MonoInst *ins, *rvar = NULL;
6065         MonoMethodHeader *cheader;
6066         MonoBasicBlock *ebblock, *sbblock;
6067         int i, costs;
6068         MonoMethod *prev_inlined_method;
6069         MonoInst **prev_locals, **prev_args;
6070         MonoType **prev_arg_types;
6071         guint prev_real_offset;
6072         GHashTable *prev_cbb_hash;
6073         MonoBasicBlock **prev_cil_offset_to_bb;
6074         MonoBasicBlock *prev_cbb;
6075         unsigned char* prev_cil_start;
6076         guint32 prev_cil_offset_to_bb_len;
6077         MonoMethod *prev_current_method;
6078         MonoGenericContext *prev_generic_context;
6079         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6080
6081         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6082
6083 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6084         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6085                 return 0;
6086 #endif
6087 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6088         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6089                 return 0;
6090 #endif
6091
6092         if (cfg->verbose_level > 2)
6093                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6094
6095         if (!cmethod->inline_info) {
6096                 cfg->stat_inlineable_methods++;
6097                 cmethod->inline_info = 1;
6098         }
6099
6100         /* allocate local variables */
6101         cheader = mono_method_get_header (cmethod);
6102
6103         if (cheader == NULL || mono_loader_get_last_error ()) {
6104                 MonoLoaderError *error = mono_loader_get_last_error ();
6105
6106                 if (cheader)
6107                         mono_metadata_free_mh (cheader);
6108                 if (inline_always && error)
6109                         mono_cfg_set_exception (cfg, error->exception_type);
6110
6111                 mono_loader_clear_error ();
6112                 return 0;
6113         }
6114
6115         /*Must verify before creating locals as it can cause the JIT to assert.*/
6116         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6117                 mono_metadata_free_mh (cheader);
6118                 return 0;
6119         }
6120
6121         /* allocate space to store the return value */
6122         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6123                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6124         }
6125
6126         prev_locals = cfg->locals;
6127         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6128         for (i = 0; i < cheader->num_locals; ++i)
6129                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6130
6131         /* allocate start and end blocks */
6132         /* This is needed so if the inline is aborted, we can clean up */
6133         NEW_BBLOCK (cfg, sbblock);
6134         sbblock->real_offset = real_offset;
6135
6136         NEW_BBLOCK (cfg, ebblock);
6137         ebblock->block_num = cfg->num_bblocks++;
6138         ebblock->real_offset = real_offset;
6139
6140         prev_args = cfg->args;
6141         prev_arg_types = cfg->arg_types;
6142         prev_inlined_method = cfg->inlined_method;
6143         cfg->inlined_method = cmethod;
6144         cfg->ret_var_set = FALSE;
6145         cfg->inline_depth ++;
6146         prev_real_offset = cfg->real_offset;
6147         prev_cbb_hash = cfg->cbb_hash;
6148         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6149         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6150         prev_cil_start = cfg->cil_start;
6151         prev_cbb = cfg->cbb;
6152         prev_current_method = cfg->current_method;
6153         prev_generic_context = cfg->generic_context;
6154         prev_ret_var_set = cfg->ret_var_set;
6155         prev_disable_inline = cfg->disable_inline;
6156
6157         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6158                 virtual = TRUE;
6159
6160         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6161
6162         ret_var_set = cfg->ret_var_set;
6163
6164         cfg->inlined_method = prev_inlined_method;
6165         cfg->real_offset = prev_real_offset;
6166         cfg->cbb_hash = prev_cbb_hash;
6167         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6168         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6169         cfg->cil_start = prev_cil_start;
6170         cfg->locals = prev_locals;
6171         cfg->args = prev_args;
6172         cfg->arg_types = prev_arg_types;
6173         cfg->current_method = prev_current_method;
6174         cfg->generic_context = prev_generic_context;
6175         cfg->ret_var_set = prev_ret_var_set;
6176         cfg->disable_inline = prev_disable_inline;
6177         cfg->inline_depth --;
6178
6179         if ((costs >= 0 && costs < 60) || inline_always) {
6180                 if (cfg->verbose_level > 2)
6181                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6182                 
6183                 cfg->stat_inlined_methods++;
6184
6185                 /* always add some code to avoid block split failures */
6186                 MONO_INST_NEW (cfg, ins, OP_NOP);
6187                 MONO_ADD_INS (prev_cbb, ins);
6188
6189                 prev_cbb->next_bb = sbblock;
6190                 link_bblock (cfg, prev_cbb, sbblock);
6191
6192                 /* 
6193                  * Get rid of the begin and end bblocks if possible to aid local
6194                  * optimizations.
6195                  */
6196                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6197
6198                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6199                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6200
6201                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6202                         MonoBasicBlock *prev = ebblock->in_bb [0];
6203                         mono_merge_basic_blocks (cfg, prev, ebblock);
6204                         cfg->cbb = prev;
6205                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6206                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6207                                 cfg->cbb = prev_cbb;
6208                         }
6209                 } else {
6210                         /* 
6211                          * Its possible that the rvar is set in some prev bblock, but not in others.
6212                          * (#1835).
6213                          */
6214                         if (rvar) {
6215                                 MonoBasicBlock *bb;
6216
6217                                 for (i = 0; i < ebblock->in_count; ++i) {
6218                                         bb = ebblock->in_bb [i];
6219
6220                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6221                                                 cfg->cbb = bb;
6222
6223                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6224                                         }
6225                                 }
6226                         }
6227
6228                         cfg->cbb = ebblock;
6229                 }
6230
6231                 *out_cbb = cfg->cbb;
6232
6233                 if (rvar) {
6234                         /*
6235                          * If the inlined method contains only a throw, then the ret var is not 
6236                          * set, so set it to a dummy value.
6237                          */
6238                         if (!ret_var_set)
6239                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6240
6241                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6242                         *sp++ = ins;
6243                 }
6244                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6245                 return costs + 1;
6246         } else {
6247                 if (cfg->verbose_level > 2)
6248                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6249                 cfg->exception_type = MONO_EXCEPTION_NONE;
6250                 mono_loader_clear_error ();
6251
6252                 /* This gets rid of the newly added bblocks */
6253                 cfg->cbb = prev_cbb;
6254         }
6255         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6256         return 0;
6257 }
6258
6259 /*
6260  * Some of these comments may well be out-of-date.
6261  * Design decisions: we do a single pass over the IL code (and we do bblock 
6262  * splitting/merging in the few cases when it's required: a back jump to an IL
6263  * address that was not already seen as bblock starting point).
6264  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6265  * Complex operations are decomposed in simpler ones right away. We need to let the 
6266  * arch-specific code peek and poke inside this process somehow (except when the 
6267  * optimizations can take advantage of the full semantic info of coarse opcodes).
6268  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6269  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6270  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6271  * opcode with value bigger than OP_LAST.
6272  * At this point the IR can be handed over to an interpreter, a dumb code generator
6273  * or to the optimizing code generator that will translate it to SSA form.
6274  *
6275  * Profiling directed optimizations.
6276  * We may compile by default with few or no optimizations and instrument the code
6277  * or the user may indicate what methods to optimize the most either in a config file
6278  * or through repeated runs where the compiler applies offline the optimizations to 
6279  * each method and then decides if it was worth it.
6280  */
6281
6282 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6283 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6284 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6285 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6286 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6287 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6288 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6289 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
6290
6291 /* offset from br.s -> br like opcodes */
6292 #define BIG_BRANCH_OFFSET 13
6293
6294 static gboolean
6295 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6296 {
6297         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6298
6299         return b == NULL || b == bb;
6300 }
6301
6302 static int
6303 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6304 {
6305         unsigned char *ip = start;
6306         unsigned char *target;
6307         int i;
6308         guint cli_addr;
6309         MonoBasicBlock *bblock;
6310         const MonoOpcode *opcode;
6311
6312         while (ip < end) {
6313                 cli_addr = ip - start;
6314                 i = mono_opcode_value ((const guint8 **)&ip, end);
6315                 if (i < 0)
6316                         UNVERIFIED;
6317                 opcode = &mono_opcodes [i];
6318                 switch (opcode->argument) {
6319                 case MonoInlineNone:
6320                         ip++; 
6321                         break;
6322                 case MonoInlineString:
6323                 case MonoInlineType:
6324                 case MonoInlineField:
6325                 case MonoInlineMethod:
6326                 case MonoInlineTok:
6327                 case MonoInlineSig:
6328                 case MonoShortInlineR:
6329                 case MonoInlineI:
6330                         ip += 5;
6331                         break;
6332                 case MonoInlineVar:
6333                         ip += 3;
6334                         break;
6335                 case MonoShortInlineVar:
6336                 case MonoShortInlineI:
6337                         ip += 2;
6338                         break;
6339                 case MonoShortInlineBrTarget:
6340                         target = start + cli_addr + 2 + (signed char)ip [1];
6341                         GET_BBLOCK (cfg, bblock, target);
6342                         ip += 2;
6343                         if (ip < end)
6344                                 GET_BBLOCK (cfg, bblock, ip);
6345                         break;
6346                 case MonoInlineBrTarget:
6347                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6348                         GET_BBLOCK (cfg, bblock, target);
6349                         ip += 5;
6350                         if (ip < end)
6351                                 GET_BBLOCK (cfg, bblock, ip);
6352                         break;
6353                 case MonoInlineSwitch: {
6354                         guint32 n = read32 (ip + 1);
6355                         guint32 j;
6356                         ip += 5;
6357                         cli_addr += 5 + 4 * n;
6358                         target = start + cli_addr;
6359                         GET_BBLOCK (cfg, bblock, target);
6360                         
6361                         for (j = 0; j < n; ++j) {
6362                                 target = start + cli_addr + (gint32)read32 (ip);
6363                                 GET_BBLOCK (cfg, bblock, target);
6364                                 ip += 4;
6365                         }
6366                         break;
6367                 }
6368                 case MonoInlineR:
6369                 case MonoInlineI8:
6370                         ip += 9;
6371                         break;
6372                 default:
6373                         g_assert_not_reached ();
6374                 }
6375
6376                 if (i == CEE_THROW) {
6377                         unsigned char *bb_start = ip - 1;
6378                         
6379                         /* Find the start of the bblock containing the throw */
6380                         bblock = NULL;
6381                         while ((bb_start >= start) && !bblock) {
6382                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6383                                 bb_start --;
6384                         }
6385                         if (bblock)
6386                                 bblock->out_of_line = 1;
6387                 }
6388         }
6389         return 0;
6390 unverified:
6391 exception_exit:
6392         *pos = ip;
6393         return 1;
6394 }
6395
6396 static inline MonoMethod *
6397 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6398 {
6399         MonoMethod *method;
6400
6401         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6402                 method = mono_method_get_wrapper_data (m, token);
6403                 if (context)
6404                         method = mono_class_inflate_generic_method (method, context);
6405         } else {
6406                 method = mono_get_method_full (m->klass->image, token, klass, context);
6407         }
6408
6409         return method;
6410 }
6411
6412 static inline MonoMethod *
6413 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6414 {
6415         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6416
6417         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6418                 return NULL;
6419
6420         return method;
6421 }
6422
6423 static inline MonoClass*
6424 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6425 {
6426         MonoError error;
6427         MonoClass *klass;
6428
6429         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6430                 klass = mono_method_get_wrapper_data (method, token);
6431                 if (context)
6432                         klass = mono_class_inflate_generic_class (klass, context);
6433         } else {
6434                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6435                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6436         }
6437         if (klass)
6438                 mono_class_init (klass);
6439         return klass;
6440 }
6441
6442 static inline MonoMethodSignature*
6443 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6444 {
6445         MonoMethodSignature *fsig;
6446
6447         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6448                 MonoError error;
6449
6450                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6451                 if (context) {
6452                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6453                         // FIXME:
6454                         g_assert (mono_error_ok (&error));
6455                 }
6456         } else {
6457                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6458         }
6459         return fsig;
6460 }
6461
6462 /*
6463  * Returns TRUE if the JIT should abort inlining because "callee"
6464  * is influenced by security attributes.
6465  */
6466 static
6467 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6468 {
6469         guint32 result;
6470         
6471         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6472                 return TRUE;
6473         }
6474         
6475         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6476         if (result == MONO_JIT_SECURITY_OK)
6477                 return FALSE;
6478
6479         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6480                 /* Generate code to throw a SecurityException before the actual call/link */
6481                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6482                 MonoInst *args [2];
6483
6484                 NEW_ICONST (cfg, args [0], 4);
6485                 NEW_METHODCONST (cfg, args [1], caller);
6486                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6487         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6488                  /* don't hide previous results */
6489                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6490                 cfg->exception_data = result;
6491                 return TRUE;
6492         }
6493         
6494         return FALSE;
6495 }
6496
6497 static MonoMethod*
6498 throw_exception (void)
6499 {
6500         static MonoMethod *method = NULL;
6501
6502         if (!method) {
6503                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6504                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6505         }
6506         g_assert (method);
6507         return method;
6508 }
6509
6510 static void
6511 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6512 {
6513         MonoMethod *thrower = throw_exception ();
6514         MonoInst *args [1];
6515
6516         EMIT_NEW_PCONST (cfg, args [0], ex);
6517         mono_emit_method_call (cfg, thrower, args, NULL);
6518 }
6519
6520 /*
6521  * Return the original method is a wrapper is specified. We can only access 
6522  * the custom attributes from the original method.
6523  */
6524 static MonoMethod*
6525 get_original_method (MonoMethod *method)
6526 {
6527         if (method->wrapper_type == MONO_WRAPPER_NONE)
6528                 return method;
6529
6530         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6531         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6532                 return NULL;
6533
6534         /* in other cases we need to find the original method */
6535         return mono_marshal_method_from_wrapper (method);
6536 }
6537
6538 static void
6539 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6540                                           MonoBasicBlock *bblock, unsigned char *ip)
6541 {
6542         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6543         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6544         if (ex)
6545                 emit_throw_exception (cfg, ex);
6546 }
6547
6548 static void
6549 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6550                                          MonoBasicBlock *bblock, unsigned char *ip)
6551 {
6552         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6553         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6554         if (ex)
6555                 emit_throw_exception (cfg, ex);
6556 }
6557
6558 /*
6559  * Check that the IL instructions at ip are the array initialization
6560  * sequence and return the pointer to the data and the size.
6561  */
6562 static const char*
6563 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6564 {
6565         /*
6566          * newarr[System.Int32]
6567          * dup
6568          * ldtoken field valuetype ...
6569          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6570          */
6571         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6572                 guint32 token = read32 (ip + 7);
6573                 guint32 field_token = read32 (ip + 2);
6574                 guint32 field_index = field_token & 0xffffff;
6575                 guint32 rva;
6576                 const char *data_ptr;
6577                 int size = 0;
6578                 MonoMethod *cmethod;
6579                 MonoClass *dummy_class;
6580                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6581                 int dummy_align;
6582
6583                 if (!field)
6584                         return NULL;
6585
6586                 *out_field_token = field_token;
6587
6588                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6589                 if (!cmethod)
6590                         return NULL;
6591                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6592                         return NULL;
6593                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6594                 case MONO_TYPE_BOOLEAN:
6595                 case MONO_TYPE_I1:
6596                 case MONO_TYPE_U1:
6597                         size = 1; break;
6598                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6599 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6600                 case MONO_TYPE_CHAR:
6601                 case MONO_TYPE_I2:
6602                 case MONO_TYPE_U2:
6603                         size = 2; break;
6604                 case MONO_TYPE_I4:
6605                 case MONO_TYPE_U4:
6606                 case MONO_TYPE_R4:
6607                         size = 4; break;
6608                 case MONO_TYPE_R8:
6609                 case MONO_TYPE_I8:
6610                 case MONO_TYPE_U8:
6611                         size = 8; break;
6612 #endif
6613                 default:
6614                         return NULL;
6615                 }
6616                 size *= len;
6617                 if (size > mono_type_size (field->type, &dummy_align))
6618                     return NULL;
6619                 *out_size = size;
6620                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6621                 if (!image_is_dynamic (method->klass->image)) {
6622                         field_index = read32 (ip + 2) & 0xffffff;
6623                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6624                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6625                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6626                         /* for aot code we do the lookup on load */
6627                         if (aot && data_ptr)
6628                                 return GUINT_TO_POINTER (rva);
6629                 } else {
6630                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6631                         g_assert (!aot);
6632                         data_ptr = mono_field_get_data (field);
6633                 }
6634                 return data_ptr;
6635         }
6636         return NULL;
6637 }
6638
6639 static void
6640 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6641 {
6642         char *method_fname = mono_method_full_name (method, TRUE);
6643         char *method_code;
6644         MonoMethodHeader *header = mono_method_get_header (method);
6645
6646         if (header->code_size == 0)
6647                 method_code = g_strdup ("method body is empty.");
6648         else
6649                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6650         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6651         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6652         g_free (method_fname);
6653         g_free (method_code);
6654         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6655 }
6656
6657 static void
6658 set_exception_object (MonoCompile *cfg, MonoException *exception)
6659 {
6660         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6661         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6662         cfg->exception_ptr = exception;
6663 }
6664
6665 static void
6666 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6667 {
6668         MonoInst *ins;
6669         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6670         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6671                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6672                 /* Optimize reg-reg moves away */
6673                 /* 
6674                  * Can't optimize other opcodes, since sp[0] might point to
6675                  * the last ins of a decomposed opcode.
6676                  */
6677                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6678         } else {
6679                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6680         }
6681 }
6682
6683 /*
6684  * ldloca inhibits many optimizations so try to get rid of it in common
6685  * cases.
6686  */
6687 static inline unsigned char *
6688 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6689 {
6690         int local, token;
6691         MonoClass *klass;
6692         MonoType *type;
6693
6694         if (size == 1) {
6695                 local = ip [1];
6696                 ip += 2;
6697         } else {
6698                 local = read16 (ip + 2);
6699                 ip += 4;
6700         }
6701         
6702         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6703                 /* From the INITOBJ case */
6704                 token = read32 (ip + 2);
6705                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6706                 CHECK_TYPELOAD (klass);
6707                 type = mini_replace_type (&klass->byval_arg);
6708                 emit_init_local (cfg, local, type, TRUE);
6709                 return ip + 6;
6710         }
6711  exception_exit:
6712         return NULL;
6713 }
6714
6715 static gboolean
6716 is_exception_class (MonoClass *class)
6717 {
6718         while (class) {
6719                 if (class == mono_defaults.exception_class)
6720                         return TRUE;
6721                 class = class->parent;
6722         }
6723         return FALSE;
6724 }
6725
6726 /*
6727  * is_jit_optimizer_disabled:
6728  *
6729  *   Determine whenever M's assembly has a DebuggableAttribute with the
6730  * IsJITOptimizerDisabled flag set.
6731  */
6732 static gboolean
6733 is_jit_optimizer_disabled (MonoMethod *m)
6734 {
6735         MonoAssembly *ass = m->klass->image->assembly;
6736         MonoCustomAttrInfo* attrs;
6737         static MonoClass *klass;
6738         int i;
6739         gboolean val = FALSE;
6740
6741         g_assert (ass);
6742         if (ass->jit_optimizer_disabled_inited)
6743                 return ass->jit_optimizer_disabled;
6744
6745         if (!klass)
6746                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6747         if (!klass) {
6748                 /* Linked away */
6749                 ass->jit_optimizer_disabled = FALSE;
6750                 mono_memory_barrier ();
6751                 ass->jit_optimizer_disabled_inited = TRUE;
6752                 return FALSE;
6753         }
6754
6755         attrs = mono_custom_attrs_from_assembly (ass);
6756         if (attrs) {
6757                 for (i = 0; i < attrs->num_attrs; ++i) {
6758                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6759                         const gchar *p;
6760                         int len;
6761                         MonoMethodSignature *sig;
6762
6763                         if (!attr->ctor || attr->ctor->klass != klass)
6764                                 continue;
6765                         /* Decode the attribute. See reflection.c */
6766                         len = attr->data_size;
6767                         p = (const char*)attr->data;
6768                         g_assert (read16 (p) == 0x0001);
6769                         p += 2;
6770
6771                         // FIXME: Support named parameters
6772                         sig = mono_method_signature (attr->ctor);
6773                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6774                                 continue;
6775                         /* Two boolean arguments */
6776                         p ++;
6777                         val = *p;
6778                 }
6779                 mono_custom_attrs_free (attrs);
6780         }
6781
6782         ass->jit_optimizer_disabled = val;
6783         mono_memory_barrier ();
6784         ass->jit_optimizer_disabled_inited = TRUE;
6785
6786         return val;
6787 }
6788
6789 static gboolean
6790 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
6791 {
6792         gboolean supported_tail_call;
6793         int i;
6794
6795 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
6796         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
6797 #else
6798         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6799 #endif
6800
6801         for (i = 0; i < fsig->param_count; ++i) {
6802                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6803                         /* These can point to the current method's stack */
6804                         supported_tail_call = FALSE;
6805         }
6806         if (fsig->hasthis && cmethod->klass->valuetype)
6807                 /* this might point to the current method's stack */
6808                 supported_tail_call = FALSE;
6809         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6810                 supported_tail_call = FALSE;
6811         if (cfg->method->save_lmf)
6812                 supported_tail_call = FALSE;
6813         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6814                 supported_tail_call = FALSE;
6815         if (call_opcode != CEE_CALL)
6816                 supported_tail_call = FALSE;
6817
6818         /* Debugging support */
6819 #if 0
6820         if (supported_tail_call) {
6821                 if (!mono_debug_count ())
6822                         supported_tail_call = FALSE;
6823         }
6824 #endif
6825
6826         return supported_tail_call;
6827 }
6828
6829 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6830  * it to the thread local value based on the tls_offset field. Every other kind of access to
6831  * the field causes an assert.
6832  */
6833 static gboolean
6834 is_magic_tls_access (MonoClassField *field)
6835 {
6836         if (strcmp (field->name, "tlsdata"))
6837                 return FALSE;
6838         if (strcmp (field->parent->name, "ThreadLocal`1"))
6839                 return FALSE;
6840         return field->parent->image == mono_defaults.corlib;
6841 }
6842
6843 /* emits the code needed to access a managed tls var (like ThreadStatic)
6844  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6845  * pointer for the current thread.
6846  * Returns the MonoInst* representing the address of the tls var.
6847  */
6848 static MonoInst*
6849 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6850 {
6851         MonoInst *addr;
6852         int static_data_reg, array_reg, dreg;
6853         int offset2_reg, idx_reg;
6854         // inlined access to the tls data
6855         // idx = (offset >> 24) - 1;
6856         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6857         static_data_reg = alloc_ireg (cfg);
6858         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
6859         idx_reg = alloc_ireg (cfg);
6860         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6861         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6862         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6863         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6864         array_reg = alloc_ireg (cfg);
6865         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6866         offset2_reg = alloc_ireg (cfg);
6867         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6868         dreg = alloc_ireg (cfg);
6869         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6870         return addr;
6871 }
6872
6873 /*
6874  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6875  * this address is cached per-method in cached_tls_addr.
6876  */
6877 static MonoInst*
6878 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6879 {
6880         MonoInst *load, *addr, *temp, *store, *thread_ins;
6881         MonoClassField *offset_field;
6882
6883         if (*cached_tls_addr) {
6884                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6885                 return addr;
6886         }
6887         thread_ins = mono_get_thread_intrinsic (cfg);
6888         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6889
6890         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6891         if (thread_ins) {
6892                 MONO_ADD_INS (cfg->cbb, thread_ins);
6893         } else {
6894                 MonoMethod *thread_method;
6895                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6896                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6897         }
6898         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6899         addr->klass = mono_class_from_mono_type (tls_field->type);
6900         addr->type = STACK_MP;
6901         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6902         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6903
6904         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6905         return addr;
6906 }
6907
6908 /*
6909  * handle_ctor_call:
6910  *
6911  *   Handle calls made to ctors from NEWOBJ opcodes.
6912  *
6913  *   REF_BBLOCK will point to the current bblock after the call.
6914  */
6915 static void
6916 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
6917                                   MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
6918 {
6919         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
6920         MonoBasicBlock *bblock = *ref_bblock;
6921
6922         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
6923                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
6924                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
6925                         mono_class_vtable (cfg->domain, cmethod->klass);
6926                         CHECK_TYPELOAD (cmethod->klass);
6927
6928                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
6929                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
6930                 } else {
6931                         if (context_used) {
6932                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
6933                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
6934                         } else {
6935                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6936
6937                                 CHECK_TYPELOAD (cmethod->klass);
6938                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
6939                         }
6940                 }
6941         }
6942
6943         /* Avoid virtual calls to ctors if possible */
6944         if (mono_class_is_marshalbyref (cmethod->klass))
6945                 callvirt_this_arg = sp [0];
6946
6947         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
6948                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
6949                 CHECK_CFG_EXCEPTION;
6950         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
6951                            mono_method_check_inlining (cfg, cmethod) &&
6952                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
6953                 int costs;
6954
6955                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
6956                         cfg->real_offset += 5;
6957
6958                         *inline_costs += costs - 5;
6959                         *ref_bblock = bblock;
6960                 } else {
6961                         INLINE_FAILURE ("inline failure");
6962                         // FIXME-VT: Clean this up
6963                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
6964                                 GSHAREDVT_FAILURE(*ip);
6965                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
6966                 }
6967         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
6968                 MonoInst *addr;
6969
6970                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
6971                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
6972         } else if (context_used &&
6973                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
6974                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
6975                 MonoInst *cmethod_addr;
6976
6977                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
6978
6979                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
6980                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
6981
6982                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
6983         } else {
6984                 INLINE_FAILURE ("ctor call");
6985                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
6986                                                                                   callvirt_this_arg, NULL, vtable_arg);
6987         }
6988  exception_exit:
6989         return;
6990 }
6991
6992 /*
6993  * mono_method_to_ir:
6994  *
6995  *   Translate the .net IL into linear IR.
6996  */
6997 int
6998 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6999                    MonoInst *return_var, MonoInst **inline_args, 
7000                    guint inline_offset, gboolean is_virtual_call)
7001 {
7002         MonoError error;
7003         MonoInst *ins, **sp, **stack_start;
7004         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
7005         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7006         MonoMethod *cmethod, *method_definition;
7007         MonoInst **arg_array;
7008         MonoMethodHeader *header;
7009         MonoImage *image;
7010         guint32 token, ins_flag;
7011         MonoClass *klass;
7012         MonoClass *constrained_call = NULL;
7013         unsigned char *ip, *end, *target, *err_pos;
7014         MonoMethodSignature *sig;
7015         MonoGenericContext *generic_context = NULL;
7016         MonoGenericContainer *generic_container = NULL;
7017         MonoType **param_types;
7018         int i, n, start_new_bblock, dreg;
7019         int num_calls = 0, inline_costs = 0;
7020         int breakpoint_id = 0;
7021         guint num_args;
7022         MonoBoolean security, pinvoke;
7023         MonoSecurityManager* secman = NULL;
7024         MonoDeclSecurityActions actions;
7025         GSList *class_inits = NULL;
7026         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7027         int context_used;
7028         gboolean init_locals, seq_points, skip_dead_blocks;
7029         gboolean sym_seq_points = FALSE;
7030         MonoInst *cached_tls_addr = NULL;
7031         MonoDebugMethodInfo *minfo;
7032         MonoBitSet *seq_point_locs = NULL;
7033         MonoBitSet *seq_point_set_locs = NULL;
7034
7035         cfg->disable_inline = is_jit_optimizer_disabled (method);
7036
7037         /* serialization and xdomain stuff may need access to private fields and methods */
7038         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7039         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7040         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7041         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7042         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7043         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7044
7045         dont_verify |= mono_security_smcs_hack_enabled ();
7046
7047         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7048         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7049         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7050         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7051         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7052
7053         image = method->klass->image;
7054         header = mono_method_get_header (method);
7055         if (!header) {
7056                 MonoLoaderError *error;
7057
7058                 if ((error = mono_loader_get_last_error ())) {
7059                         mono_cfg_set_exception (cfg, error->exception_type);
7060                 } else {
7061                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7062                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7063                 }
7064                 goto exception_exit;
7065         }
7066         generic_container = mono_method_get_generic_container (method);
7067         sig = mono_method_signature (method);
7068         num_args = sig->hasthis + sig->param_count;
7069         ip = (unsigned char*)header->code;
7070         cfg->cil_start = ip;
7071         end = ip + header->code_size;
7072         cfg->stat_cil_code_size += header->code_size;
7073
7074         seq_points = cfg->gen_seq_points && cfg->method == method;
7075 #ifdef PLATFORM_ANDROID
7076         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
7077 #endif
7078
7079         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7080                 /* We could hit a seq point before attaching to the JIT (#8338) */
7081                 seq_points = FALSE;
7082         }
7083
7084         if (cfg->gen_seq_points && cfg->method == method) {
7085                 minfo = mono_debug_lookup_method (method);
7086                 if (minfo) {
7087                         int i, n_il_offsets;
7088                         int *il_offsets;
7089                         int *line_numbers;
7090
7091                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
7092                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7093                         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);
7094                         sym_seq_points = TRUE;
7095                         for (i = 0; i < n_il_offsets; ++i) {
7096                                 if (il_offsets [i] < header->code_size)
7097                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
7098                         }
7099                         g_free (il_offsets);
7100                         g_free (line_numbers);
7101                 }
7102         }
7103
7104         /* 
7105          * Methods without init_locals set could cause asserts in various passes
7106          * (#497220). To work around this, we emit dummy initialization opcodes
7107          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7108          * on some platforms.
7109          */
7110         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7111                 init_locals = header->init_locals;
7112         else
7113                 init_locals = TRUE;
7114
7115         method_definition = method;
7116         while (method_definition->is_inflated) {
7117                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7118                 method_definition = imethod->declaring;
7119         }
7120
7121         /* SkipVerification is not allowed if core-clr is enabled */
7122         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7123                 dont_verify = TRUE;
7124                 dont_verify_stloc = TRUE;
7125         }
7126
7127         if (sig->is_inflated)
7128                 generic_context = mono_method_get_context (method);
7129         else if (generic_container)
7130                 generic_context = &generic_container->context;
7131         cfg->generic_context = generic_context;
7132
7133         if (!cfg->generic_sharing_context)
7134                 g_assert (!sig->has_type_parameters);
7135
7136         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7137                 g_assert (method->is_inflated);
7138                 g_assert (mono_method_get_context (method)->method_inst);
7139         }
7140         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7141                 g_assert (sig->generic_param_count);
7142
7143         if (cfg->method == method) {
7144                 cfg->real_offset = 0;
7145         } else {
7146                 cfg->real_offset = inline_offset;
7147         }
7148
7149         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7150         cfg->cil_offset_to_bb_len = header->code_size;
7151
7152         cfg->current_method = method;
7153
7154         if (cfg->verbose_level > 2)
7155                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7156
7157         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7158         if (sig->hasthis)
7159                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7160         for (n = 0; n < sig->param_count; ++n)
7161                 param_types [n + sig->hasthis] = sig->params [n];
7162         cfg->arg_types = param_types;
7163
7164         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7165         if (cfg->method == method) {
7166
7167                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7168                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7169
7170                 /* ENTRY BLOCK */
7171                 NEW_BBLOCK (cfg, start_bblock);
7172                 cfg->bb_entry = start_bblock;
7173                 start_bblock->cil_code = NULL;
7174                 start_bblock->cil_length = 0;
7175 #if defined(__native_client_codegen__)
7176                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
7177                 ins->dreg = alloc_dreg (cfg, STACK_I4);
7178                 MONO_ADD_INS (start_bblock, ins);
7179 #endif
7180
7181                 /* EXIT BLOCK */
7182                 NEW_BBLOCK (cfg, end_bblock);
7183                 cfg->bb_exit = end_bblock;
7184                 end_bblock->cil_code = NULL;
7185                 end_bblock->cil_length = 0;
7186                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7187                 g_assert (cfg->num_bblocks == 2);
7188
7189                 arg_array = cfg->args;
7190
7191                 if (header->num_clauses) {
7192                         cfg->spvars = g_hash_table_new (NULL, NULL);
7193                         cfg->exvars = g_hash_table_new (NULL, NULL);
7194                 }
7195                 /* handle exception clauses */
7196                 for (i = 0; i < header->num_clauses; ++i) {
7197                         MonoBasicBlock *try_bb;
7198                         MonoExceptionClause *clause = &header->clauses [i];
7199                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7200                         try_bb->real_offset = clause->try_offset;
7201                         try_bb->try_start = TRUE;
7202                         try_bb->region = ((i + 1) << 8) | clause->flags;
7203                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7204                         tblock->real_offset = clause->handler_offset;
7205                         tblock->flags |= BB_EXCEPTION_HANDLER;
7206
7207                         /*
7208                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7209                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7210                          */
7211                         if (COMPILE_LLVM (cfg))
7212                                 link_bblock (cfg, try_bb, tblock);
7213
7214                         if (*(ip + clause->handler_offset) == CEE_POP)
7215                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7216
7217                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7218                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7219                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7220                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7221                                 MONO_ADD_INS (tblock, ins);
7222
7223                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7224                                         /* finally clauses already have a seq point */
7225                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7226                                         MONO_ADD_INS (tblock, ins);
7227                                 }
7228
7229                                 /* todo: is a fault block unsafe to optimize? */
7230                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7231                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7232                         }
7233
7234
7235                         /*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);
7236                           while (p < end) {
7237                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7238                           }*/
7239                         /* catch and filter blocks get the exception object on the stack */
7240                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7241                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7242                                 MonoInst *dummy_use;
7243
7244                                 /* mostly like handle_stack_args (), but just sets the input args */
7245                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7246                                 tblock->in_scount = 1;
7247                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7248                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7249
7250                                 /* 
7251                                  * Add a dummy use for the exvar so its liveness info will be
7252                                  * correct.
7253                                  */
7254                                 cfg->cbb = tblock;
7255                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7256                                 
7257                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7258                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7259                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7260                                         tblock->real_offset = clause->data.filter_offset;
7261                                         tblock->in_scount = 1;
7262                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7263                                         /* The filter block shares the exvar with the handler block */
7264                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7265                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7266                                         MONO_ADD_INS (tblock, ins);
7267                                 }
7268                         }
7269
7270                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7271                                         clause->data.catch_class &&
7272                                         cfg->generic_sharing_context &&
7273                                         mono_class_check_context_used (clause->data.catch_class)) {
7274                                 /*
7275                                  * In shared generic code with catch
7276                                  * clauses containing type variables
7277                                  * the exception handling code has to
7278                                  * be able to get to the rgctx.
7279                                  * Therefore we have to make sure that
7280                                  * the vtable/mrgctx argument (for
7281                                  * static or generic methods) or the
7282                                  * "this" argument (for non-static
7283                                  * methods) are live.
7284                                  */
7285                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7286                                                 mini_method_get_context (method)->method_inst ||
7287                                                 method->klass->valuetype) {
7288                                         mono_get_vtable_var (cfg);
7289                                 } else {
7290                                         MonoInst *dummy_use;
7291
7292                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7293                                 }
7294                         }
7295                 }
7296         } else {
7297                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7298                 cfg->cbb = start_bblock;
7299                 cfg->args = arg_array;
7300                 mono_save_args (cfg, sig, inline_args);
7301         }
7302
7303         /* FIRST CODE BLOCK */
7304         NEW_BBLOCK (cfg, bblock);
7305         bblock->cil_code = ip;
7306         cfg->cbb = bblock;
7307         cfg->ip = ip;
7308
7309         ADD_BBLOCK (cfg, bblock);
7310
7311         if (cfg->method == method) {
7312                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7313                 if (breakpoint_id) {
7314                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7315                         MONO_ADD_INS (bblock, ins);
7316                 }
7317         }
7318
7319         if (mono_security_cas_enabled ())
7320                 secman = mono_security_manager_get_methods ();
7321
7322         security = (secman && mono_security_method_has_declsec (method));
7323         /* at this point having security doesn't mean we have any code to generate */
7324         if (security && (cfg->method == method)) {
7325                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
7326                  * And we do not want to enter the next section (with allocation) if we
7327                  * have nothing to generate */
7328                 security = mono_declsec_get_demands (method, &actions);
7329         }
7330
7331         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
7332         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
7333         if (pinvoke) {
7334                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7335                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7336                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
7337
7338                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
7339                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7340                                 pinvoke = FALSE;
7341                         }
7342                         if (custom)
7343                                 mono_custom_attrs_free (custom);
7344
7345                         if (pinvoke) {
7346                                 custom = mono_custom_attrs_from_class (wrapped->klass);
7347                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7348                                         pinvoke = FALSE;
7349                                 }
7350                                 if (custom)
7351                                         mono_custom_attrs_free (custom);
7352                         }
7353                 } else {
7354                         /* not a P/Invoke after all */
7355                         pinvoke = FALSE;
7356                 }
7357         }
7358         
7359         /* we use a separate basic block for the initialization code */
7360         NEW_BBLOCK (cfg, init_localsbb);
7361         cfg->bb_init = init_localsbb;
7362         init_localsbb->real_offset = cfg->real_offset;
7363         start_bblock->next_bb = init_localsbb;
7364         init_localsbb->next_bb = bblock;
7365         link_bblock (cfg, start_bblock, init_localsbb);
7366         link_bblock (cfg, init_localsbb, bblock);
7367                 
7368         cfg->cbb = init_localsbb;
7369
7370         if (cfg->gsharedvt && cfg->method == method) {
7371                 MonoGSharedVtMethodInfo *info;
7372                 MonoInst *var, *locals_var;
7373                 int dreg;
7374
7375                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7376                 info->method = cfg->method;
7377                 info->count_entries = 16;
7378                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7379                 cfg->gsharedvt_info = info;
7380
7381                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7382                 /* prevent it from being register allocated */
7383                 //var->flags |= MONO_INST_VOLATILE;
7384                 cfg->gsharedvt_info_var = var;
7385
7386                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7387                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7388
7389                 /* Allocate locals */
7390                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7391                 /* prevent it from being register allocated */
7392                 //locals_var->flags |= MONO_INST_VOLATILE;
7393                 cfg->gsharedvt_locals_var = locals_var;
7394
7395                 dreg = alloc_ireg (cfg);
7396                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7397
7398                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7399                 ins->dreg = locals_var->dreg;
7400                 ins->sreg1 = dreg;
7401                 MONO_ADD_INS (cfg->cbb, ins);
7402                 cfg->gsharedvt_locals_var_ins = ins;
7403                 
7404                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7405                 /*
7406                 if (init_locals)
7407                         ins->flags |= MONO_INST_INIT;
7408                 */
7409         }
7410
7411         /* at this point we know, if security is TRUE, that some code needs to be generated */
7412         if (security && (cfg->method == method)) {
7413                 MonoInst *args [2];
7414
7415                 cfg->stat_cas_demand_generation++;
7416
7417                 if (actions.demand.blob) {
7418                         /* Add code for SecurityAction.Demand */
7419                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
7420                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
7421                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7422                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7423                 }
7424                 if (actions.noncasdemand.blob) {
7425                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7426                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7427                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7428                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7429                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7430                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7431                 }
7432                 if (actions.demandchoice.blob) {
7433                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7434                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7435                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7436                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7437                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7438                 }
7439         }
7440
7441         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7442         if (pinvoke) {
7443                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7444         }
7445
7446         if (mono_security_core_clr_enabled ()) {
7447                 /* check if this is native code, e.g. an icall or a p/invoke */
7448                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7449                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7450                         if (wrapped) {
7451                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7452                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7453
7454                                 /* if this ia a native call then it can only be JITted from platform code */
7455                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7456                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7457                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7458                                                         mono_get_exception_method_access ();
7459                                                 emit_throw_exception (cfg, ex);
7460                                         }
7461                                 }
7462                         }
7463                 }
7464         }
7465
7466         CHECK_CFG_EXCEPTION;
7467
7468         if (header->code_size == 0)
7469                 UNVERIFIED;
7470
7471         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7472                 ip = err_pos;
7473                 UNVERIFIED;
7474         }
7475
7476         if (cfg->method == method)
7477                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7478
7479         for (n = 0; n < header->num_locals; ++n) {
7480                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7481                         UNVERIFIED;
7482         }
7483         class_inits = NULL;
7484
7485         /* We force the vtable variable here for all shared methods
7486            for the possibility that they might show up in a stack
7487            trace where their exact instantiation is needed. */
7488         if (cfg->generic_sharing_context && method == cfg->method) {
7489                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7490                                 mini_method_get_context (method)->method_inst ||
7491                                 method->klass->valuetype) {
7492                         mono_get_vtable_var (cfg);
7493                 } else {
7494                         /* FIXME: Is there a better way to do this?
7495                            We need the variable live for the duration
7496                            of the whole method. */
7497                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7498                 }
7499         }
7500
7501         /* add a check for this != NULL to inlined methods */
7502         if (is_virtual_call) {
7503                 MonoInst *arg_ins;
7504
7505                 NEW_ARGLOAD (cfg, arg_ins, 0);
7506                 MONO_ADD_INS (cfg->cbb, arg_ins);
7507                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7508         }
7509
7510         skip_dead_blocks = !dont_verify;
7511         if (skip_dead_blocks) {
7512                 original_bb = bb = mono_basic_block_split (method, &error);
7513                 if (!mono_error_ok (&error)) {
7514                         mono_error_cleanup (&error);
7515                         UNVERIFIED;
7516                 }
7517                 g_assert (bb);
7518         }
7519
7520         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7521         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7522
7523         ins_flag = 0;
7524         start_new_bblock = 0;
7525         cfg->cbb = bblock;
7526         while (ip < end) {
7527                 if (cfg->method == method)
7528                         cfg->real_offset = ip - header->code;
7529                 else
7530                         cfg->real_offset = inline_offset;
7531                 cfg->ip = ip;
7532
7533                 context_used = 0;
7534                 
7535                 if (start_new_bblock) {
7536                         bblock->cil_length = ip - bblock->cil_code;
7537                         if (start_new_bblock == 2) {
7538                                 g_assert (ip == tblock->cil_code);
7539                         } else {
7540                                 GET_BBLOCK (cfg, tblock, ip);
7541                         }
7542                         bblock->next_bb = tblock;
7543                         bblock = tblock;
7544                         cfg->cbb = bblock;
7545                         start_new_bblock = 0;
7546                         for (i = 0; i < bblock->in_scount; ++i) {
7547                                 if (cfg->verbose_level > 3)
7548                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7549                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7550                                 *sp++ = ins;
7551                         }
7552                         if (class_inits)
7553                                 g_slist_free (class_inits);
7554                         class_inits = NULL;
7555                 } else {
7556                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7557                                 link_bblock (cfg, bblock, tblock);
7558                                 if (sp != stack_start) {
7559                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7560                                         sp = stack_start;
7561                                         CHECK_UNVERIFIABLE (cfg);
7562                                 }
7563                                 bblock->next_bb = tblock;
7564                                 bblock = tblock;
7565                                 cfg->cbb = bblock;
7566                                 for (i = 0; i < bblock->in_scount; ++i) {
7567                                         if (cfg->verbose_level > 3)
7568                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7569                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7570                                         *sp++ = ins;
7571                                 }
7572                                 g_slist_free (class_inits);
7573                                 class_inits = NULL;
7574                         }
7575                 }
7576
7577                 if (skip_dead_blocks) {
7578                         int ip_offset = ip - header->code;
7579
7580                         if (ip_offset == bb->end)
7581                                 bb = bb->next;
7582
7583                         if (bb->dead) {
7584                                 int op_size = mono_opcode_size (ip, end);
7585                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7586
7587                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7588
7589                                 if (ip_offset + op_size == bb->end) {
7590                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7591                                         MONO_ADD_INS (bblock, ins);
7592                                         start_new_bblock = 1;
7593                                 }
7594
7595                                 ip += op_size;
7596                                 continue;
7597                         }
7598                 }
7599                 /*
7600                  * Sequence points are points where the debugger can place a breakpoint.
7601                  * Currently, we generate these automatically at points where the IL
7602                  * stack is empty.
7603                  */
7604                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7605                         /*
7606                          * Make methods interruptable at the beginning, and at the targets of
7607                          * backward branches.
7608                          * Also, do this at the start of every bblock in methods with clauses too,
7609                          * to be able to handle instructions with inprecise control flow like
7610                          * throw/endfinally.
7611                          * Backward branches are handled at the end of method-to-ir ().
7612                          */
7613                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7614
7615                         /* Avoid sequence points on empty IL like .volatile */
7616                         // FIXME: Enable this
7617                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7618                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7619                         if (sp != stack_start)
7620                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7621                         MONO_ADD_INS (cfg->cbb, ins);
7622
7623                         if (sym_seq_points)
7624                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7625                 }
7626
7627                 bblock->real_offset = cfg->real_offset;
7628
7629                 if ((cfg->method == method) && cfg->coverage_info) {
7630                         guint32 cil_offset = ip - header->code;
7631                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7632
7633                         /* TODO: Use an increment here */
7634 #if defined(TARGET_X86)
7635                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7636                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7637                         ins->inst_imm = 1;
7638                         MONO_ADD_INS (cfg->cbb, ins);
7639 #else
7640                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7641                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7642 #endif
7643                 }
7644
7645                 if (cfg->verbose_level > 3)
7646                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7647
7648                 switch (*ip) {
7649                 case CEE_NOP:
7650                         if (seq_points && !sym_seq_points && sp != stack_start) {
7651                                 /*
7652                                  * The C# compiler uses these nops to notify the JIT that it should
7653                                  * insert seq points.
7654                                  */
7655                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7656                                 MONO_ADD_INS (cfg->cbb, ins);
7657                         }
7658                         if (cfg->keep_cil_nops)
7659                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7660                         else
7661                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7662                         ip++;
7663                         MONO_ADD_INS (bblock, ins);
7664                         break;
7665                 case CEE_BREAK:
7666                         if (should_insert_brekpoint (cfg->method)) {
7667                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7668                         } else {
7669                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7670                         }
7671                         ip++;
7672                         MONO_ADD_INS (bblock, ins);
7673                         break;
7674                 case CEE_LDARG_0:
7675                 case CEE_LDARG_1:
7676                 case CEE_LDARG_2:
7677                 case CEE_LDARG_3:
7678                         CHECK_STACK_OVF (1);
7679                         n = (*ip)-CEE_LDARG_0;
7680                         CHECK_ARG (n);
7681                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7682                         ip++;
7683                         *sp++ = ins;
7684                         break;
7685                 case CEE_LDLOC_0:
7686                 case CEE_LDLOC_1:
7687                 case CEE_LDLOC_2:
7688                 case CEE_LDLOC_3:
7689                         CHECK_STACK_OVF (1);
7690                         n = (*ip)-CEE_LDLOC_0;
7691                         CHECK_LOCAL (n);
7692                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7693                         ip++;
7694                         *sp++ = ins;
7695                         break;
7696                 case CEE_STLOC_0:
7697                 case CEE_STLOC_1:
7698                 case CEE_STLOC_2:
7699                 case CEE_STLOC_3: {
7700                         CHECK_STACK (1);
7701                         n = (*ip)-CEE_STLOC_0;
7702                         CHECK_LOCAL (n);
7703                         --sp;
7704                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7705                                 UNVERIFIED;
7706                         emit_stloc_ir (cfg, sp, header, n);
7707                         ++ip;
7708                         inline_costs += 1;
7709                         break;
7710                         }
7711                 case CEE_LDARG_S:
7712                         CHECK_OPSIZE (2);
7713                         CHECK_STACK_OVF (1);
7714                         n = ip [1];
7715                         CHECK_ARG (n);
7716                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7717                         *sp++ = ins;
7718                         ip += 2;
7719                         break;
7720                 case CEE_LDARGA_S:
7721                         CHECK_OPSIZE (2);
7722                         CHECK_STACK_OVF (1);
7723                         n = ip [1];
7724                         CHECK_ARG (n);
7725                         NEW_ARGLOADA (cfg, ins, n);
7726                         MONO_ADD_INS (cfg->cbb, ins);
7727                         *sp++ = ins;
7728                         ip += 2;
7729                         break;
7730                 case CEE_STARG_S:
7731                         CHECK_OPSIZE (2);
7732                         CHECK_STACK (1);
7733                         --sp;
7734                         n = ip [1];
7735                         CHECK_ARG (n);
7736                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7737                                 UNVERIFIED;
7738                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7739                         ip += 2;
7740                         break;
7741                 case CEE_LDLOC_S:
7742                         CHECK_OPSIZE (2);
7743                         CHECK_STACK_OVF (1);
7744                         n = ip [1];
7745                         CHECK_LOCAL (n);
7746                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7747                         *sp++ = ins;
7748                         ip += 2;
7749                         break;
7750                 case CEE_LDLOCA_S: {
7751                         unsigned char *tmp_ip;
7752                         CHECK_OPSIZE (2);
7753                         CHECK_STACK_OVF (1);
7754                         CHECK_LOCAL (ip [1]);
7755
7756                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7757                                 ip = tmp_ip;
7758                                 inline_costs += 1;
7759                                 break;
7760                         }
7761
7762                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7763                         *sp++ = ins;
7764                         ip += 2;
7765                         break;
7766                 }
7767                 case CEE_STLOC_S:
7768                         CHECK_OPSIZE (2);
7769                         CHECK_STACK (1);
7770                         --sp;
7771                         CHECK_LOCAL (ip [1]);
7772                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7773                                 UNVERIFIED;
7774                         emit_stloc_ir (cfg, sp, header, ip [1]);
7775                         ip += 2;
7776                         inline_costs += 1;
7777                         break;
7778                 case CEE_LDNULL:
7779                         CHECK_STACK_OVF (1);
7780                         EMIT_NEW_PCONST (cfg, ins, NULL);
7781                         ins->type = STACK_OBJ;
7782                         ++ip;
7783                         *sp++ = ins;
7784                         break;
7785                 case CEE_LDC_I4_M1:
7786                         CHECK_STACK_OVF (1);
7787                         EMIT_NEW_ICONST (cfg, ins, -1);
7788                         ++ip;
7789                         *sp++ = ins;
7790                         break;
7791                 case CEE_LDC_I4_0:
7792                 case CEE_LDC_I4_1:
7793                 case CEE_LDC_I4_2:
7794                 case CEE_LDC_I4_3:
7795                 case CEE_LDC_I4_4:
7796                 case CEE_LDC_I4_5:
7797                 case CEE_LDC_I4_6:
7798                 case CEE_LDC_I4_7:
7799                 case CEE_LDC_I4_8:
7800                         CHECK_STACK_OVF (1);
7801                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7802                         ++ip;
7803                         *sp++ = ins;
7804                         break;
7805                 case CEE_LDC_I4_S:
7806                         CHECK_OPSIZE (2);
7807                         CHECK_STACK_OVF (1);
7808                         ++ip;
7809                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7810                         ++ip;
7811                         *sp++ = ins;
7812                         break;
7813                 case CEE_LDC_I4:
7814                         CHECK_OPSIZE (5);
7815                         CHECK_STACK_OVF (1);
7816                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7817                         ip += 5;
7818                         *sp++ = ins;
7819                         break;
7820                 case CEE_LDC_I8:
7821                         CHECK_OPSIZE (9);
7822                         CHECK_STACK_OVF (1);
7823                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7824                         ins->type = STACK_I8;
7825                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7826                         ++ip;
7827                         ins->inst_l = (gint64)read64 (ip);
7828                         MONO_ADD_INS (bblock, ins);
7829                         ip += 8;
7830                         *sp++ = ins;
7831                         break;
7832                 case CEE_LDC_R4: {
7833                         float *f;
7834                         gboolean use_aotconst = FALSE;
7835
7836 #ifdef TARGET_POWERPC
7837                         /* FIXME: Clean this up */
7838                         if (cfg->compile_aot)
7839                                 use_aotconst = TRUE;
7840 #endif
7841
7842                         /* FIXME: we should really allocate this only late in the compilation process */
7843                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7844                         CHECK_OPSIZE (5);
7845                         CHECK_STACK_OVF (1);
7846
7847                         if (use_aotconst) {
7848                                 MonoInst *cons;
7849                                 int dreg;
7850
7851                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7852
7853                                 dreg = alloc_freg (cfg);
7854                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7855                                 ins->type = STACK_R8;
7856                         } else {
7857                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7858                                 ins->type = STACK_R8;
7859                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7860                                 ins->inst_p0 = f;
7861                                 MONO_ADD_INS (bblock, ins);
7862                         }
7863                         ++ip;
7864                         readr4 (ip, f);
7865                         ip += 4;
7866                         *sp++ = ins;                    
7867                         break;
7868                 }
7869                 case CEE_LDC_R8: {
7870                         double *d;
7871                         gboolean use_aotconst = FALSE;
7872
7873 #ifdef TARGET_POWERPC
7874                         /* FIXME: Clean this up */
7875                         if (cfg->compile_aot)
7876                                 use_aotconst = TRUE;
7877 #endif
7878
7879                         /* FIXME: we should really allocate this only late in the compilation process */
7880                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7881                         CHECK_OPSIZE (9);
7882                         CHECK_STACK_OVF (1);
7883
7884                         if (use_aotconst) {
7885                                 MonoInst *cons;
7886                                 int dreg;
7887
7888                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7889
7890                                 dreg = alloc_freg (cfg);
7891                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7892                                 ins->type = STACK_R8;
7893                         } else {
7894                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7895                                 ins->type = STACK_R8;
7896                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7897                                 ins->inst_p0 = d;
7898                                 MONO_ADD_INS (bblock, ins);
7899                         }
7900                         ++ip;
7901                         readr8 (ip, d);
7902                         ip += 8;
7903                         *sp++ = ins;
7904                         break;
7905                 }
7906                 case CEE_DUP: {
7907                         MonoInst *temp, *store;
7908                         CHECK_STACK (1);
7909                         CHECK_STACK_OVF (1);
7910                         sp--;
7911                         ins = *sp;
7912
7913                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7914                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7915
7916                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7917                         *sp++ = ins;
7918
7919                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7920                         *sp++ = ins;
7921
7922                         ++ip;
7923                         inline_costs += 2;
7924                         break;
7925                 }
7926                 case CEE_POP:
7927                         CHECK_STACK (1);
7928                         ip++;
7929                         --sp;
7930
7931 #ifdef TARGET_X86
7932                         if (sp [0]->type == STACK_R8)
7933                                 /* we need to pop the value from the x86 FP stack */
7934                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7935 #endif
7936                         break;
7937                 case CEE_JMP: {
7938                         MonoCallInst *call;
7939
7940                         INLINE_FAILURE ("jmp");
7941                         GSHAREDVT_FAILURE (*ip);
7942
7943                         CHECK_OPSIZE (5);
7944                         if (stack_start != sp)
7945                                 UNVERIFIED;
7946                         token = read32 (ip + 1);
7947                         /* FIXME: check the signature matches */
7948                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7949
7950                         if (!cmethod || mono_loader_get_last_error ())
7951                                 LOAD_ERROR;
7952  
7953                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7954                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7955
7956                         if (mono_security_cas_enabled ())
7957                                 CHECK_CFG_EXCEPTION;
7958
7959                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
7960
7961                         if (ARCH_HAVE_OP_TAIL_CALL) {
7962                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7963                                 int i, n;
7964
7965                                 /* Handle tail calls similarly to calls */
7966                                 n = fsig->param_count + fsig->hasthis;
7967
7968                                 DISABLE_AOT (cfg);
7969
7970                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7971                                 call->method = cmethod;
7972                                 call->tail_call = TRUE;
7973                                 call->signature = mono_method_signature (cmethod);
7974                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7975                                 call->inst.inst_p0 = cmethod;
7976                                 for (i = 0; i < n; ++i)
7977                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7978
7979                                 mono_arch_emit_call (cfg, call);
7980                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
7981                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7982                         } else {
7983                                 for (i = 0; i < num_args; ++i)
7984                                         /* Prevent arguments from being optimized away */
7985                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
7986
7987                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7988                                 ins = (MonoInst*)call;
7989                                 ins->inst_p0 = cmethod;
7990                                 MONO_ADD_INS (bblock, ins);
7991                         }
7992
7993                         ip += 5;
7994                         start_new_bblock = 1;
7995                         break;
7996                 }
7997                 case CEE_CALLI:
7998                 case CEE_CALL:
7999                 case CEE_CALLVIRT: {
8000                         MonoInst *addr = NULL;
8001                         MonoMethodSignature *fsig = NULL;
8002                         int array_rank = 0;
8003                         int virtual = *ip == CEE_CALLVIRT;
8004                         int calli = *ip == CEE_CALLI;
8005                         gboolean pass_imt_from_rgctx = FALSE;
8006                         MonoInst *imt_arg = NULL;
8007                         MonoInst *keep_this_alive = NULL;
8008                         gboolean pass_vtable = FALSE;
8009                         gboolean pass_mrgctx = FALSE;
8010                         MonoInst *vtable_arg = NULL;
8011                         gboolean check_this = FALSE;
8012                         gboolean supported_tail_call = FALSE;
8013                         gboolean tail_call = FALSE;
8014                         gboolean need_seq_point = FALSE;
8015                         guint32 call_opcode = *ip;
8016                         gboolean emit_widen = TRUE;
8017                         gboolean push_res = TRUE;
8018                         gboolean skip_ret = FALSE;
8019                         gboolean delegate_invoke = FALSE;
8020
8021                         CHECK_OPSIZE (5);
8022                         token = read32 (ip + 1);
8023
8024                         ins = NULL;
8025
8026                         if (calli) {
8027                                 //GSHAREDVT_FAILURE (*ip);
8028                                 cmethod = NULL;
8029                                 CHECK_STACK (1);
8030                                 --sp;
8031                                 addr = *sp;
8032                                 fsig = mini_get_signature (method, token, generic_context);
8033                                 n = fsig->param_count + fsig->hasthis;
8034
8035                                 if (method->dynamic && fsig->pinvoke) {
8036                                         MonoInst *args [3];
8037
8038                                         /*
8039                                          * This is a call through a function pointer using a pinvoke
8040                                          * signature. Have to create a wrapper and call that instead.
8041                                          * FIXME: This is very slow, need to create a wrapper at JIT time
8042                                          * instead based on the signature.
8043                                          */
8044                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8045                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
8046                                         args [2] = addr;
8047                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8048                                 }
8049                         } else {
8050                                 MonoMethod *cil_method;
8051
8052                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8053                                 cil_method = cmethod;
8054                                 
8055                                 if (constrained_call) {
8056                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8057                                                 if (cfg->verbose_level > 2)
8058                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8059                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
8060                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
8061                                                           cfg->generic_sharing_context)) {
8062                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
8063                                                 }
8064                                         } else {
8065                                                 if (cfg->verbose_level > 2)
8066                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8067
8068                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8069                                                         /* 
8070                                                          * This is needed since get_method_constrained can't find 
8071                                                          * the method in klass representing a type var.
8072                                                          * The type var is guaranteed to be a reference type in this
8073                                                          * case.
8074                                                          */
8075                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
8076                                                                 g_assert (!cmethod->klass->valuetype);
8077                                                 } else {
8078                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
8079                                                 }
8080                                         }
8081                                 }
8082                                         
8083                                 if (!cmethod || mono_loader_get_last_error ())
8084                                         LOAD_ERROR;
8085                                 if (!dont_verify && !cfg->skip_visibility) {
8086                                         MonoMethod *target_method = cil_method;
8087                                         if (method->is_inflated) {
8088                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8089                                         }
8090                                         if (!mono_method_can_access_method (method_definition, target_method) &&
8091                                                 !mono_method_can_access_method (method, cil_method))
8092                                                 METHOD_ACCESS_FAILURE (method, cil_method);
8093                                 }
8094
8095                                 if (mono_security_core_clr_enabled ())
8096                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
8097
8098                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8099                                         /* MS.NET seems to silently convert this to a callvirt */
8100                                         virtual = 1;
8101
8102                                 {
8103                                         /*
8104                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8105                                          * converts to a callvirt.
8106                                          *
8107                                          * tests/bug-515884.il is an example of this behavior
8108                                          */
8109                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8110                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8111                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8112                                                 virtual = 1;
8113                                 }
8114
8115                                 if (!cmethod->klass->inited)
8116                                         if (!mono_class_init (cmethod->klass))
8117                                                 TYPE_LOAD_ERROR (cmethod->klass);
8118
8119                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8120                                     mini_class_is_system_array (cmethod->klass)) {
8121                                         array_rank = cmethod->klass->rank;
8122                                         fsig = mono_method_signature (cmethod);
8123                                 } else {
8124                                         fsig = mono_method_signature (cmethod);
8125
8126                                         if (!fsig)
8127                                                 LOAD_ERROR;
8128
8129                                         if (fsig->pinvoke) {
8130                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8131                                                         check_for_pending_exc, cfg->compile_aot);
8132                                                 fsig = mono_method_signature (wrapper);
8133                                         } else if (constrained_call) {
8134                                                 fsig = mono_method_signature (cmethod);
8135                                         } else {
8136                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
8137                                         }
8138                                 }
8139
8140                                 mono_save_token_info (cfg, image, token, cil_method);
8141
8142                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8143                                         /*
8144                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
8145                                          * foo (bar (), baz ())
8146                                          * works correctly. MS does this also:
8147                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
8148                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
8149                                          * even for simple cases, like:
8150                                          * int i = foo ();
8151                                          */
8152                                         /* Special case a few common successor opcodes */
8153                                         if (!(ip + 5 < end && (ip [5] == CEE_POP || ip [5] == CEE_NOP)) && !(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8154                                                 need_seq_point = TRUE;
8155                                 }
8156
8157                                 n = fsig->param_count + fsig->hasthis;
8158
8159                                 /* Don't support calls made using type arguments for now */
8160                                 /*
8161                                 if (cfg->gsharedvt) {
8162                                         if (mini_is_gsharedvt_signature (cfg, fsig))
8163                                                 GSHAREDVT_FAILURE (*ip);
8164                                 }
8165                                 */
8166
8167                                 if (mono_security_cas_enabled ()) {
8168                                         if (check_linkdemand (cfg, method, cmethod))
8169                                                 INLINE_FAILURE ("linkdemand");
8170                                         CHECK_CFG_EXCEPTION;
8171                                 }
8172
8173                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8174                                         g_assert_not_reached ();
8175                         }
8176
8177                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
8178                                 UNVERIFIED;
8179
8180                         if (!cfg->generic_sharing_context && cmethod)
8181                                 g_assert (!mono_method_check_context_used (cmethod));
8182
8183                         CHECK_STACK (n);
8184
8185                         //g_assert (!virtual || fsig->hasthis);
8186
8187                         sp -= n;
8188
8189                         if (constrained_call) {
8190                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
8191                                         /*
8192                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
8193                                          */
8194                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
8195                                                 /* The 'Own method' case below */
8196                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8197                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8198                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
8199                                                            (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)) &&
8200                                                            (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || mini_is_gsharedvt_type (cfg, fsig->params [0]))))) {
8201                                                 MonoInst *args [16];
8202
8203                                                 /*
8204                                                  * This case handles calls to
8205                                                  * - object:ToString()/Equals()/GetHashCode(),
8206                                                  * - System.IComparable<T>:CompareTo()
8207                                                  * - System.IEquatable<T>:Equals ()
8208                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
8209                                                  */
8210
8211                                                 args [0] = sp [0];
8212                                                 if (mono_method_check_context_used (cmethod))
8213                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
8214                                                 else
8215                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
8216                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
8217
8218                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
8219                                                 if (fsig->hasthis && fsig->param_count) {
8220                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
8221                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
8222                                                         ins->dreg = alloc_preg (cfg);
8223                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
8224                                                         MONO_ADD_INS (cfg->cbb, ins);
8225                                                         args [4] = ins;
8226
8227                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
8228                                                                 int addr_reg;
8229
8230                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
8231
8232                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
8233                                                                 addr_reg = ins->dreg;
8234                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
8235                                                         } else {
8236                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
8237                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
8238                                                         }
8239                                                 } else {
8240                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
8241                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
8242                                                 }
8243                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
8244                                                 emit_widen = FALSE;
8245
8246                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
8247                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
8248                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
8249                                                         MonoInst *add;
8250
8251                                                         /* Unbox */
8252                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
8253                                                         MONO_ADD_INS (cfg->cbb, add);
8254                                                         /* Load value */
8255                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
8256                                                         MONO_ADD_INS (cfg->cbb, ins);
8257                                                         /* ins represents the call result */
8258                                                 }
8259
8260                                                 goto call_end;
8261                                         } else {
8262                                                 GSHAREDVT_FAILURE (*ip);
8263                                         }
8264                                 }
8265                                 /*
8266                                  * We have the `constrained.' prefix opcode.
8267                                  */
8268                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8269                                         /*
8270                                          * The type parameter is instantiated as a valuetype,
8271                                          * but that type doesn't override the method we're
8272                                          * calling, so we need to box `this'.
8273                                          */
8274                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8275                                         ins->klass = constrained_call;
8276                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8277                                         CHECK_CFG_EXCEPTION;
8278                                 } else if (!constrained_call->valuetype) {
8279                                         int dreg = alloc_ireg_ref (cfg);
8280
8281                                         /*
8282                                          * The type parameter is instantiated as a reference
8283                                          * type.  We have a managed pointer on the stack, so
8284                                          * we need to dereference it here.
8285                                          */
8286                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8287                                         ins->type = STACK_OBJ;
8288                                         sp [0] = ins;
8289                                 } else {
8290                                         if (cmethod->klass->valuetype) {
8291                                                 /* Own method */
8292                                         } else {
8293                                                 /* Interface method */
8294                                                 int ioffset, slot;
8295
8296                                                 mono_class_setup_vtable (constrained_call);
8297                                                 CHECK_TYPELOAD (constrained_call);
8298                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8299                                                 if (ioffset == -1)
8300                                                         TYPE_LOAD_ERROR (constrained_call);
8301                                                 slot = mono_method_get_vtable_slot (cmethod);
8302                                                 if (slot == -1)
8303                                                         TYPE_LOAD_ERROR (cmethod->klass);
8304                                                 cmethod = constrained_call->vtable [ioffset + slot];
8305
8306                                                 if (cmethod->klass == mono_defaults.enum_class) {
8307                                                         /* Enum implements some interfaces, so treat this as the first case */
8308                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8309                                                         ins->klass = constrained_call;
8310                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8311                                                         CHECK_CFG_EXCEPTION;
8312                                                 }
8313                                         }
8314                                         virtual = 0;
8315                                 }
8316                                 constrained_call = NULL;
8317                         }
8318
8319                         if (!calli && check_call_signature (cfg, fsig, sp))
8320                                 UNVERIFIED;
8321
8322 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8323                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8324                                 delegate_invoke = TRUE;
8325 #endif
8326
8327                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8328                                 bblock = cfg->cbb;
8329                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8330                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8331                                         emit_widen = FALSE;
8332                                 }
8333
8334                                 goto call_end;
8335                         }
8336
8337                         /* 
8338                          * If the callee is a shared method, then its static cctor
8339                          * might not get called after the call was patched.
8340                          */
8341                         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)) {
8342                                 emit_generic_class_init (cfg, cmethod->klass);
8343                                 CHECK_TYPELOAD (cmethod->klass);
8344                         }
8345
8346                         if (cmethod)
8347                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8348
8349                         if (cfg->generic_sharing_context && cmethod) {
8350                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8351
8352                                 context_used = mini_method_check_context_used (cfg, cmethod);
8353
8354                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8355                                         /* Generic method interface
8356                                            calls are resolved via a
8357                                            helper function and don't
8358                                            need an imt. */
8359                                         if (!cmethod_context || !cmethod_context->method_inst)
8360                                                 pass_imt_from_rgctx = TRUE;
8361                                 }
8362
8363                                 /*
8364                                  * If a shared method calls another
8365                                  * shared method then the caller must
8366                                  * have a generic sharing context
8367                                  * because the magic trampoline
8368                                  * requires it.  FIXME: We shouldn't
8369                                  * have to force the vtable/mrgctx
8370                                  * variable here.  Instead there
8371                                  * should be a flag in the cfg to
8372                                  * request a generic sharing context.
8373                                  */
8374                                 if (context_used &&
8375                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8376                                         mono_get_vtable_var (cfg);
8377                         }
8378
8379                         if (pass_vtable) {
8380                                 if (context_used) {
8381                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8382                                 } else {
8383                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8384
8385                                         CHECK_TYPELOAD (cmethod->klass);
8386                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8387                                 }
8388                         }
8389
8390                         if (pass_mrgctx) {
8391                                 g_assert (!vtable_arg);
8392
8393                                 if (!cfg->compile_aot) {
8394                                         /* 
8395                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8396                                          * for type load errors before.
8397                                          */
8398                                         mono_class_setup_vtable (cmethod->klass);
8399                                         CHECK_TYPELOAD (cmethod->klass);
8400                                 }
8401
8402                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8403
8404                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8405                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8406                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8407                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8408                                         if (virtual)
8409                                                 check_this = TRUE;
8410                                         virtual = 0;
8411                                 }
8412                         }
8413
8414                         if (pass_imt_from_rgctx) {
8415                                 g_assert (!pass_vtable);
8416                                 g_assert (cmethod);
8417
8418                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8419                                         cmethod, MONO_RGCTX_INFO_METHOD);
8420                         }
8421
8422                         if (check_this)
8423                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8424
8425                         /* Calling virtual generic methods */
8426                         if (cmethod && virtual && 
8427                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8428                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8429                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8430                             fsig->generic_param_count && 
8431                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8432                                 MonoInst *this_temp, *this_arg_temp, *store;
8433                                 MonoInst *iargs [4];
8434                                 gboolean use_imt = FALSE;
8435
8436                                 g_assert (fsig->is_inflated);
8437
8438                                 /* Prevent inlining of methods that contain indirect calls */
8439                                 INLINE_FAILURE ("virtual generic call");
8440
8441                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8442                                         GSHAREDVT_FAILURE (*ip);
8443
8444 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8445                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8446                                         use_imt = TRUE;
8447 #endif
8448
8449                                 if (use_imt) {
8450                                         g_assert (!imt_arg);
8451                                         if (!context_used)
8452                                                 g_assert (cmethod->is_inflated);
8453                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8454                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8455                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8456                                 } else {
8457                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8458                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8459                                         MONO_ADD_INS (bblock, store);
8460
8461                                         /* FIXME: This should be a managed pointer */
8462                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8463
8464                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8465                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8466                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8467                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8468                                         addr = mono_emit_jit_icall (cfg,
8469                                                                                                 mono_helper_compile_generic_method, iargs);
8470
8471                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8472
8473                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8474                                 }
8475
8476                                 goto call_end;
8477                         }
8478
8479                         /*
8480                          * Implement a workaround for the inherent races involved in locking:
8481                          * Monitor.Enter ()
8482                          * try {
8483                          * } finally {
8484                          *    Monitor.Exit ()
8485                          * }
8486                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8487                          * try block, the Exit () won't be executed, see:
8488                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8489                          * To work around this, we extend such try blocks to include the last x bytes
8490                          * of the Monitor.Enter () call.
8491                          */
8492                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8493                                 MonoBasicBlock *tbb;
8494
8495                                 GET_BBLOCK (cfg, tbb, ip + 5);
8496                                 /* 
8497                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8498                                  * from Monitor.Enter like ArgumentNullException.
8499                                  */
8500                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8501                                         /* Mark this bblock as needing to be extended */
8502                                         tbb->extend_try_block = TRUE;
8503                                 }
8504                         }
8505
8506                         /* Conversion to a JIT intrinsic */
8507                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8508                                 bblock = cfg->cbb;
8509                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8510                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8511                                         emit_widen = FALSE;
8512                                 }
8513                                 goto call_end;
8514                         }
8515
8516                         /* Inlining */
8517                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8518                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8519                             mono_method_check_inlining (cfg, cmethod)) {
8520                                 int costs;
8521                                 gboolean always = FALSE;
8522
8523                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8524                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8525                                         /* Prevent inlining of methods that call wrappers */
8526                                         INLINE_FAILURE ("wrapper call");
8527                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8528                                         always = TRUE;
8529                                 }
8530
8531                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
8532                                 if (costs) {
8533                                         cfg->real_offset += 5;
8534
8535                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8536                                                 /* *sp is already set by inline_method */
8537                                                 sp++;
8538                                                 push_res = FALSE;
8539                                         }
8540
8541                                         inline_costs += costs;
8542
8543                                         goto call_end;
8544                                 }
8545                         }
8546
8547                         /* Tail recursion elimination */
8548                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8549                                 gboolean has_vtargs = FALSE;
8550                                 int i;
8551
8552                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8553                                 INLINE_FAILURE ("tail call");
8554
8555                                 /* keep it simple */
8556                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8557                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8558                                                 has_vtargs = TRUE;
8559                                 }
8560
8561                                 if (!has_vtargs) {
8562                                         for (i = 0; i < n; ++i)
8563                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8564                                         MONO_INST_NEW (cfg, ins, OP_BR);
8565                                         MONO_ADD_INS (bblock, ins);
8566                                         tblock = start_bblock->out_bb [0];
8567                                         link_bblock (cfg, bblock, tblock);
8568                                         ins->inst_target_bb = tblock;
8569                                         start_new_bblock = 1;
8570
8571                                         /* skip the CEE_RET, too */
8572                                         if (ip_in_bb (cfg, bblock, ip + 5))
8573                                                 skip_ret = TRUE;
8574                                         push_res = FALSE;
8575                                         goto call_end;
8576                                 }
8577                         }
8578
8579                         inline_costs += 10 * num_calls++;
8580
8581                         /*
8582                          * Making generic calls out of gsharedvt methods.
8583                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8584                          * patching gshared method addresses into a gsharedvt method.
8585                          */
8586                         if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class)) {
8587                                 MonoRgctxInfoType info_type;
8588
8589                                 if (virtual) {
8590                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8591                                                 //GSHAREDVT_FAILURE (*ip);
8592                                         // disable for possible remoting calls
8593                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8594                                                 GSHAREDVT_FAILURE (*ip);
8595                                         if (fsig->generic_param_count) {
8596                                                 /* virtual generic call */
8597                                                 g_assert (mono_use_imt);
8598                                                 g_assert (!imt_arg);
8599                                                 /* Same as the virtual generic case above */
8600                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8601                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8602                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8603                                                 vtable_arg = NULL;
8604                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
8605                                                 /* This can happen when we call a fully instantiated iface method */
8606                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8607                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8608                                                 vtable_arg = NULL;
8609                                         }
8610                                 }
8611
8612                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8613                                         /* test_0_multi_dim_arrays () in gshared.cs */
8614                                         GSHAREDVT_FAILURE (*ip);
8615
8616                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8617                                         keep_this_alive = sp [0];
8618
8619                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8620                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8621                                 else
8622                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8623                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8624
8625                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8626                                 goto call_end;
8627                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8628                                 /*
8629                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8630                                  */
8631                                 MonoInst *callee = addr;
8632
8633                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8634                                         /* Not tested */
8635                                         GSHAREDVT_FAILURE (*ip);
8636
8637                                 addr = emit_get_rgctx_sig (cfg, context_used,
8638                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8639                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8640                                 goto call_end;
8641                         }
8642
8643                         /* Generic sharing */
8644
8645                         /*
8646                          * Use this if the callee is gsharedvt sharable too, since
8647                          * at runtime we might find an instantiation so the call cannot
8648                          * be patched (the 'no_patch' code path in mini-trampolines.c).
8649                          */
8650                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8651                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8652                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8653                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8654                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8655                                 INLINE_FAILURE ("gshared");
8656
8657                                 g_assert (cfg->generic_sharing_context && cmethod);
8658                                 g_assert (!addr);
8659
8660                                 /*
8661                                  * We are compiling a call to a
8662                                  * generic method from shared code,
8663                                  * which means that we have to look up
8664                                  * the method in the rgctx and do an
8665                                  * indirect call.
8666                                  */
8667                                 if (fsig->hasthis)
8668                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8669
8670                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8671                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8672                                 goto call_end;
8673                         }
8674
8675                         /* Indirect calls */
8676                         if (addr) {
8677                                 if (call_opcode == CEE_CALL)
8678                                         g_assert (context_used);
8679                                 else if (call_opcode == CEE_CALLI)
8680                                         g_assert (!vtable_arg);
8681                                 else
8682                                         /* FIXME: what the hell is this??? */
8683                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8684                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8685
8686                                 /* Prevent inlining of methods with indirect calls */
8687                                 INLINE_FAILURE ("indirect call");
8688
8689                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8690                                         int info_type;
8691                                         gpointer info_data;
8692
8693                                         /* 
8694                                          * Instead of emitting an indirect call, emit a direct call
8695                                          * with the contents of the aotconst as the patch info.
8696                                          */
8697                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8698                                                 info_type = addr->inst_c1;
8699                                                 info_data = addr->inst_p0;
8700                                         } else {
8701                                                 info_type = addr->inst_right->inst_c1;
8702                                                 info_data = addr->inst_right->inst_left;
8703                                         }
8704                                         
8705                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8706                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8707                                                 NULLIFY_INS (addr);
8708                                                 goto call_end;
8709                                         }
8710                                 }
8711                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8712                                 goto call_end;
8713                         }
8714                                         
8715                         /* Array methods */
8716                         if (array_rank) {
8717                                 MonoInst *addr;
8718
8719                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8720                                         MonoInst *val = sp [fsig->param_count];
8721
8722                                         if (val->type == STACK_OBJ) {
8723                                                 MonoInst *iargs [2];
8724
8725                                                 iargs [0] = sp [0];
8726                                                 iargs [1] = val;
8727                                                 
8728                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8729                                         }
8730                                         
8731                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8732                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8733                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8734                                                 emit_write_barrier (cfg, addr, val);
8735                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8736                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8737
8738                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8739                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8740                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8741                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8742                                         CHECK_TYPELOAD (cmethod->klass);
8743                                         
8744                                         readonly = FALSE;
8745                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8746                                         ins = addr;
8747                                 } else {
8748                                         g_assert_not_reached ();
8749                                 }
8750
8751                                 emit_widen = FALSE;
8752                                 goto call_end;
8753                         }
8754
8755                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8756                         if (ins)
8757                                 goto call_end;
8758
8759                         /* Tail prefix / tail call optimization */
8760
8761                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8762                         /* FIXME: runtime generic context pointer for jumps? */
8763                         /* FIXME: handle this for generic sharing eventually */
8764                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8765                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
8766                                 supported_tail_call = TRUE;
8767
8768                         if (supported_tail_call) {
8769                                 MonoCallInst *call;
8770
8771                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8772                                 INLINE_FAILURE ("tail call");
8773
8774                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8775
8776                                 if (ARCH_HAVE_OP_TAIL_CALL) {
8777                                         /* Handle tail calls similarly to normal calls */
8778                                         tail_call = TRUE;
8779                                 } else {
8780                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8781
8782                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8783                                         call->tail_call = TRUE;
8784                                         call->method = cmethod;
8785                                         call->signature = mono_method_signature (cmethod);
8786
8787                                         /*
8788                                          * We implement tail calls by storing the actual arguments into the 
8789                                          * argument variables, then emitting a CEE_JMP.
8790                                          */
8791                                         for (i = 0; i < n; ++i) {
8792                                                 /* Prevent argument from being register allocated */
8793                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8794                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8795                                         }
8796                                         ins = (MonoInst*)call;
8797                                         ins->inst_p0 = cmethod;
8798                                         ins->inst_p1 = arg_array [0];
8799                                         MONO_ADD_INS (bblock, ins);
8800                                         link_bblock (cfg, bblock, end_bblock);                  
8801                                         start_new_bblock = 1;
8802
8803                                         // FIXME: Eliminate unreachable epilogs
8804
8805                                         /*
8806                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8807                                          * only reachable from this call.
8808                                          */
8809                                         GET_BBLOCK (cfg, tblock, ip + 5);
8810                                         if (tblock == bblock || tblock->in_count == 0)
8811                                                 skip_ret = TRUE;
8812                                         push_res = FALSE;
8813
8814                                         goto call_end;
8815                                 }
8816                         }
8817
8818                         /* 
8819                          * Synchronized wrappers.
8820                          * Its hard to determine where to replace a method with its synchronized
8821                          * wrapper without causing an infinite recursion. The current solution is
8822                          * to add the synchronized wrapper in the trampolines, and to
8823                          * change the called method to a dummy wrapper, and resolve that wrapper
8824                          * to the real method in mono_jit_compile_method ().
8825                          */
8826                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8827                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8828                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8829                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8830                         }
8831
8832                         /* Common call */
8833                         INLINE_FAILURE ("call");
8834                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8835                                                                                           imt_arg, vtable_arg);
8836
8837                         if (tail_call) {
8838                                 link_bblock (cfg, bblock, end_bblock);                  
8839                                 start_new_bblock = 1;
8840
8841                                 // FIXME: Eliminate unreachable epilogs
8842
8843                                 /*
8844                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8845                                  * only reachable from this call.
8846                                  */
8847                                 GET_BBLOCK (cfg, tblock, ip + 5);
8848                                 if (tblock == bblock || tblock->in_count == 0)
8849                                         skip_ret = TRUE;
8850                                 push_res = FALSE;
8851                         }
8852
8853                         call_end:
8854
8855                         /* End of call, INS should contain the result of the call, if any */
8856
8857                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8858                                 g_assert (ins);
8859                                 if (emit_widen)
8860                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8861                                 else
8862                                         *sp++ = ins;
8863                         }
8864
8865                         if (keep_this_alive) {
8866                                 MonoInst *dummy_use;
8867
8868                                 /* See mono_emit_method_call_full () */
8869                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8870                         }
8871
8872                         CHECK_CFG_EXCEPTION;
8873
8874                         ip += 5;
8875                         if (skip_ret) {
8876                                 g_assert (*ip == CEE_RET);
8877                                 ip += 1;
8878                         }
8879                         ins_flag = 0;
8880                         constrained_call = NULL;
8881                         if (need_seq_point)
8882                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8883                         break;
8884                 }
8885                 case CEE_RET:
8886                         if (cfg->method != method) {
8887                                 /* return from inlined method */
8888                                 /* 
8889                                  * If in_count == 0, that means the ret is unreachable due to
8890                                  * being preceeded by a throw. In that case, inline_method () will
8891                                  * handle setting the return value 
8892                                  * (test case: test_0_inline_throw ()).
8893                                  */
8894                                 if (return_var && cfg->cbb->in_count) {
8895                                         MonoType *ret_type = mono_method_signature (method)->ret;
8896
8897                                         MonoInst *store;
8898                                         CHECK_STACK (1);
8899                                         --sp;
8900
8901                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8902                                                 UNVERIFIED;
8903
8904                                         //g_assert (returnvar != -1);
8905                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8906                                         cfg->ret_var_set = TRUE;
8907                                 } 
8908                         } else {
8909                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
8910
8911                                 if (cfg->lmf_var && cfg->cbb->in_count)
8912                                         emit_pop_lmf (cfg);
8913
8914                                 if (cfg->ret) {
8915                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
8916
8917                                         if (seq_points && !sym_seq_points) {
8918                                                 /* 
8919                                                  * Place a seq point here too even through the IL stack is not
8920                                                  * empty, so a step over on
8921                                                  * call <FOO>
8922                                                  * ret
8923                                                  * will work correctly.
8924                                                  */
8925                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8926                                                 MONO_ADD_INS (cfg->cbb, ins);
8927                                         }
8928
8929                                         g_assert (!return_var);
8930                                         CHECK_STACK (1);
8931                                         --sp;
8932
8933                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8934                                                 UNVERIFIED;
8935
8936                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8937                                                 MonoInst *ret_addr;
8938
8939                                                 if (!cfg->vret_addr) {
8940                                                         MonoInst *ins;
8941
8942                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8943                                                 } else {
8944                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8945
8946                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8947                                                         ins->klass = mono_class_from_mono_type (ret_type);
8948                                                 }
8949                                         } else {
8950 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8951                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8952                                                         MonoInst *iargs [1];
8953                                                         MonoInst *conv;
8954
8955                                                         iargs [0] = *sp;
8956                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8957                                                         mono_arch_emit_setret (cfg, method, conv);
8958                                                 } else {
8959                                                         mono_arch_emit_setret (cfg, method, *sp);
8960                                                 }
8961 #else
8962                                                 mono_arch_emit_setret (cfg, method, *sp);
8963 #endif
8964                                         }
8965                                 }
8966                         }
8967                         if (sp != stack_start)
8968                                 UNVERIFIED;
8969                         MONO_INST_NEW (cfg, ins, OP_BR);
8970                         ip++;
8971                         ins->inst_target_bb = end_bblock;
8972                         MONO_ADD_INS (bblock, ins);
8973                         link_bblock (cfg, bblock, end_bblock);
8974                         start_new_bblock = 1;
8975                         break;
8976                 case CEE_BR_S:
8977                         CHECK_OPSIZE (2);
8978                         MONO_INST_NEW (cfg, ins, OP_BR);
8979                         ip++;
8980                         target = ip + 1 + (signed char)(*ip);
8981                         ++ip;
8982                         GET_BBLOCK (cfg, tblock, target);
8983                         link_bblock (cfg, bblock, tblock);
8984                         ins->inst_target_bb = tblock;
8985                         if (sp != stack_start) {
8986                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8987                                 sp = stack_start;
8988                                 CHECK_UNVERIFIABLE (cfg);
8989                         }
8990                         MONO_ADD_INS (bblock, ins);
8991                         start_new_bblock = 1;
8992                         inline_costs += BRANCH_COST;
8993                         break;
8994                 case CEE_BEQ_S:
8995                 case CEE_BGE_S:
8996                 case CEE_BGT_S:
8997                 case CEE_BLE_S:
8998                 case CEE_BLT_S:
8999                 case CEE_BNE_UN_S:
9000                 case CEE_BGE_UN_S:
9001                 case CEE_BGT_UN_S:
9002                 case CEE_BLE_UN_S:
9003                 case CEE_BLT_UN_S:
9004                         CHECK_OPSIZE (2);
9005                         CHECK_STACK (2);
9006                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9007                         ip++;
9008                         target = ip + 1 + *(signed char*)ip;
9009                         ip++;
9010
9011                         ADD_BINCOND (NULL);
9012
9013                         sp = stack_start;
9014                         inline_costs += BRANCH_COST;
9015                         break;
9016                 case CEE_BR:
9017                         CHECK_OPSIZE (5);
9018                         MONO_INST_NEW (cfg, ins, OP_BR);
9019                         ip++;
9020
9021                         target = ip + 4 + (gint32)read32(ip);
9022                         ip += 4;
9023                         GET_BBLOCK (cfg, tblock, target);
9024                         link_bblock (cfg, bblock, tblock);
9025                         ins->inst_target_bb = tblock;
9026                         if (sp != stack_start) {
9027                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9028                                 sp = stack_start;
9029                                 CHECK_UNVERIFIABLE (cfg);
9030                         }
9031
9032                         MONO_ADD_INS (bblock, ins);
9033
9034                         start_new_bblock = 1;
9035                         inline_costs += BRANCH_COST;
9036                         break;
9037                 case CEE_BRFALSE_S:
9038                 case CEE_BRTRUE_S:
9039                 case CEE_BRFALSE:
9040                 case CEE_BRTRUE: {
9041                         MonoInst *cmp;
9042                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9043                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9044                         guint32 opsize = is_short ? 1 : 4;
9045
9046                         CHECK_OPSIZE (opsize);
9047                         CHECK_STACK (1);
9048                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9049                                 UNVERIFIED;
9050                         ip ++;
9051                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9052                         ip += opsize;
9053
9054                         sp--;
9055
9056                         GET_BBLOCK (cfg, tblock, target);
9057                         link_bblock (cfg, bblock, tblock);
9058                         GET_BBLOCK (cfg, tblock, ip);
9059                         link_bblock (cfg, bblock, tblock);
9060
9061                         if (sp != stack_start) {
9062                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9063                                 CHECK_UNVERIFIABLE (cfg);
9064                         }
9065
9066                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9067                         cmp->sreg1 = sp [0]->dreg;
9068                         type_from_op (cmp, sp [0], NULL);
9069                         CHECK_TYPE (cmp);
9070
9071 #if SIZEOF_REGISTER == 4
9072                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9073                                 /* Convert it to OP_LCOMPARE */
9074                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9075                                 ins->type = STACK_I8;
9076                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9077                                 ins->inst_l = 0;
9078                                 MONO_ADD_INS (bblock, ins);
9079                                 cmp->opcode = OP_LCOMPARE;
9080                                 cmp->sreg2 = ins->dreg;
9081                         }
9082 #endif
9083                         MONO_ADD_INS (bblock, cmp);
9084
9085                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9086                         type_from_op (ins, sp [0], NULL);
9087                         MONO_ADD_INS (bblock, ins);
9088                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9089                         GET_BBLOCK (cfg, tblock, target);
9090                         ins->inst_true_bb = tblock;
9091                         GET_BBLOCK (cfg, tblock, ip);
9092                         ins->inst_false_bb = tblock;
9093                         start_new_bblock = 2;
9094
9095                         sp = stack_start;
9096                         inline_costs += BRANCH_COST;
9097                         break;
9098                 }
9099                 case CEE_BEQ:
9100                 case CEE_BGE:
9101                 case CEE_BGT:
9102                 case CEE_BLE:
9103                 case CEE_BLT:
9104                 case CEE_BNE_UN:
9105                 case CEE_BGE_UN:
9106                 case CEE_BGT_UN:
9107                 case CEE_BLE_UN:
9108                 case CEE_BLT_UN:
9109                         CHECK_OPSIZE (5);
9110                         CHECK_STACK (2);
9111                         MONO_INST_NEW (cfg, ins, *ip);
9112                         ip++;
9113                         target = ip + 4 + (gint32)read32(ip);
9114                         ip += 4;
9115
9116                         ADD_BINCOND (NULL);
9117
9118                         sp = stack_start;
9119                         inline_costs += BRANCH_COST;
9120                         break;
9121                 case CEE_SWITCH: {
9122                         MonoInst *src1;
9123                         MonoBasicBlock **targets;
9124                         MonoBasicBlock *default_bblock;
9125                         MonoJumpInfoBBTable *table;
9126                         int offset_reg = alloc_preg (cfg);
9127                         int target_reg = alloc_preg (cfg);
9128                         int table_reg = alloc_preg (cfg);
9129                         int sum_reg = alloc_preg (cfg);
9130                         gboolean use_op_switch;
9131
9132                         CHECK_OPSIZE (5);
9133                         CHECK_STACK (1);
9134                         n = read32 (ip + 1);
9135                         --sp;
9136                         src1 = sp [0];
9137                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9138                                 UNVERIFIED;
9139
9140                         ip += 5;
9141                         CHECK_OPSIZE (n * sizeof (guint32));
9142                         target = ip + n * sizeof (guint32);
9143
9144                         GET_BBLOCK (cfg, default_bblock, target);
9145                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9146
9147                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9148                         for (i = 0; i < n; ++i) {
9149                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9150                                 targets [i] = tblock;
9151                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9152                                 ip += 4;
9153                         }
9154
9155                         if (sp != stack_start) {
9156                                 /* 
9157                                  * Link the current bb with the targets as well, so handle_stack_args
9158                                  * will set their in_stack correctly.
9159                                  */
9160                                 link_bblock (cfg, bblock, default_bblock);
9161                                 for (i = 0; i < n; ++i)
9162                                         link_bblock (cfg, bblock, targets [i]);
9163
9164                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9165                                 sp = stack_start;
9166                                 CHECK_UNVERIFIABLE (cfg);
9167                         }
9168
9169                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9170                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9171                         bblock = cfg->cbb;
9172
9173                         for (i = 0; i < n; ++i)
9174                                 link_bblock (cfg, bblock, targets [i]);
9175
9176                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9177                         table->table = targets;
9178                         table->table_size = n;
9179
9180                         use_op_switch = FALSE;
9181 #ifdef TARGET_ARM
9182                         /* ARM implements SWITCH statements differently */
9183                         /* FIXME: Make it use the generic implementation */
9184                         if (!cfg->compile_aot)
9185                                 use_op_switch = TRUE;
9186 #endif
9187
9188                         if (COMPILE_LLVM (cfg))
9189                                 use_op_switch = TRUE;
9190
9191                         cfg->cbb->has_jump_table = 1;
9192
9193                         if (use_op_switch) {
9194                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9195                                 ins->sreg1 = src1->dreg;
9196                                 ins->inst_p0 = table;
9197                                 ins->inst_many_bb = targets;
9198                                 ins->klass = GUINT_TO_POINTER (n);
9199                                 MONO_ADD_INS (cfg->cbb, ins);
9200                         } else {
9201                                 if (sizeof (gpointer) == 8)
9202                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9203                                 else
9204                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9205
9206 #if SIZEOF_REGISTER == 8
9207                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9208                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9209 #endif
9210
9211                                 if (cfg->compile_aot) {
9212                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9213                                 } else {
9214                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9215                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9216                                         ins->inst_p0 = table;
9217                                         ins->dreg = table_reg;
9218                                         MONO_ADD_INS (cfg->cbb, ins);
9219                                 }
9220
9221                                 /* FIXME: Use load_memindex */
9222                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9223                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9224                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9225                         }
9226                         start_new_bblock = 1;
9227                         inline_costs += (BRANCH_COST * 2);
9228                         break;
9229                 }
9230                 case CEE_LDIND_I1:
9231                 case CEE_LDIND_U1:
9232                 case CEE_LDIND_I2:
9233                 case CEE_LDIND_U2:
9234                 case CEE_LDIND_I4:
9235                 case CEE_LDIND_U4:
9236                 case CEE_LDIND_I8:
9237                 case CEE_LDIND_I:
9238                 case CEE_LDIND_R4:
9239                 case CEE_LDIND_R8:
9240                 case CEE_LDIND_REF:
9241                         CHECK_STACK (1);
9242                         --sp;
9243
9244                         switch (*ip) {
9245                         case CEE_LDIND_R4:
9246                         case CEE_LDIND_R8:
9247                                 dreg = alloc_freg (cfg);
9248                                 break;
9249                         case CEE_LDIND_I8:
9250                                 dreg = alloc_lreg (cfg);
9251                                 break;
9252                         case CEE_LDIND_REF:
9253                                 dreg = alloc_ireg_ref (cfg);
9254                                 break;
9255                         default:
9256                                 dreg = alloc_preg (cfg);
9257                         }
9258
9259                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9260                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9261                         ins->flags |= ins_flag;
9262                         MONO_ADD_INS (bblock, ins);
9263                         *sp++ = ins;
9264                         if (ins_flag & MONO_INST_VOLATILE) {
9265                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9266                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9267                                 emit_memory_barrier (cfg, FullBarrier);
9268                         }
9269                         ins_flag = 0;
9270                         ++ip;
9271                         break;
9272                 case CEE_STIND_REF:
9273                 case CEE_STIND_I1:
9274                 case CEE_STIND_I2:
9275                 case CEE_STIND_I4:
9276                 case CEE_STIND_I8:
9277                 case CEE_STIND_R4:
9278                 case CEE_STIND_R8:
9279                 case CEE_STIND_I:
9280                         CHECK_STACK (2);
9281                         sp -= 2;
9282
9283                         if (ins_flag & MONO_INST_VOLATILE) {
9284                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9285                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9286                                 emit_memory_barrier (cfg, FullBarrier);
9287                         }
9288
9289                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9290                         ins->flags |= ins_flag;
9291                         ins_flag = 0;
9292
9293                         MONO_ADD_INS (bblock, ins);
9294
9295                         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)))
9296                                 emit_write_barrier (cfg, sp [0], sp [1]);
9297
9298                         inline_costs += 1;
9299                         ++ip;
9300                         break;
9301
9302                 case CEE_MUL:
9303                         CHECK_STACK (2);
9304
9305                         MONO_INST_NEW (cfg, ins, (*ip));
9306                         sp -= 2;
9307                         ins->sreg1 = sp [0]->dreg;
9308                         ins->sreg2 = sp [1]->dreg;
9309                         type_from_op (ins, sp [0], sp [1]);
9310                         CHECK_TYPE (ins);
9311                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9312
9313                         /* Use the immediate opcodes if possible */
9314                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9315                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9316                                 if (imm_opcode != -1) {
9317                                         ins->opcode = imm_opcode;
9318                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9319                                         ins->sreg2 = -1;
9320
9321                                         sp [1]->opcode = OP_NOP;
9322                                 }
9323                         }
9324
9325                         MONO_ADD_INS ((cfg)->cbb, (ins));
9326
9327                         *sp++ = mono_decompose_opcode (cfg, ins);
9328                         ip++;
9329                         break;
9330                 case CEE_ADD:
9331                 case CEE_SUB:
9332                 case CEE_DIV:
9333                 case CEE_DIV_UN:
9334                 case CEE_REM:
9335                 case CEE_REM_UN:
9336                 case CEE_AND:
9337                 case CEE_OR:
9338                 case CEE_XOR:
9339                 case CEE_SHL:
9340                 case CEE_SHR:
9341                 case CEE_SHR_UN:
9342                         CHECK_STACK (2);
9343
9344                         MONO_INST_NEW (cfg, ins, (*ip));
9345                         sp -= 2;
9346                         ins->sreg1 = sp [0]->dreg;
9347                         ins->sreg2 = sp [1]->dreg;
9348                         type_from_op (ins, sp [0], sp [1]);
9349                         CHECK_TYPE (ins);
9350                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
9351                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9352
9353                         /* FIXME: Pass opcode to is_inst_imm */
9354
9355                         /* Use the immediate opcodes if possible */
9356                         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)) {
9357                                 int imm_opcode;
9358
9359                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9360 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9361                                 /* Keep emulated opcodes which are optimized away later */
9362                                 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) {
9363                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9364                                 }
9365 #endif
9366                                 if (imm_opcode != -1) {
9367                                         ins->opcode = imm_opcode;
9368                                         if (sp [1]->opcode == OP_I8CONST) {
9369 #if SIZEOF_REGISTER == 8
9370                                                 ins->inst_imm = sp [1]->inst_l;
9371 #else
9372                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9373                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9374 #endif
9375                                         }
9376                                         else
9377                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9378                                         ins->sreg2 = -1;
9379
9380                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
9381                                         if (sp [1]->next == NULL)
9382                                                 sp [1]->opcode = OP_NOP;
9383                                 }
9384                         }
9385                         MONO_ADD_INS ((cfg)->cbb, (ins));
9386
9387                         *sp++ = mono_decompose_opcode (cfg, ins);
9388                         ip++;
9389                         break;
9390                 case CEE_NEG:
9391                 case CEE_NOT:
9392                 case CEE_CONV_I1:
9393                 case CEE_CONV_I2:
9394                 case CEE_CONV_I4:
9395                 case CEE_CONV_R4:
9396                 case CEE_CONV_R8:
9397                 case CEE_CONV_U4:
9398                 case CEE_CONV_I8:
9399                 case CEE_CONV_U8:
9400                 case CEE_CONV_OVF_I8:
9401                 case CEE_CONV_OVF_U8:
9402                 case CEE_CONV_R_UN:
9403                         CHECK_STACK (1);
9404
9405                         /* Special case this earlier so we have long constants in the IR */
9406                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9407                                 int data = sp [-1]->inst_c0;
9408                                 sp [-1]->opcode = OP_I8CONST;
9409                                 sp [-1]->type = STACK_I8;
9410 #if SIZEOF_REGISTER == 8
9411                                 if ((*ip) == CEE_CONV_U8)
9412                                         sp [-1]->inst_c0 = (guint32)data;
9413                                 else
9414                                         sp [-1]->inst_c0 = data;
9415 #else
9416                                 sp [-1]->inst_ls_word = data;
9417                                 if ((*ip) == CEE_CONV_U8)
9418                                         sp [-1]->inst_ms_word = 0;
9419                                 else
9420                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9421 #endif
9422                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9423                         }
9424                         else {
9425                                 ADD_UNOP (*ip);
9426                         }
9427                         ip++;
9428                         break;
9429                 case CEE_CONV_OVF_I4:
9430                 case CEE_CONV_OVF_I1:
9431                 case CEE_CONV_OVF_I2:
9432                 case CEE_CONV_OVF_I:
9433                 case CEE_CONV_OVF_U:
9434                         CHECK_STACK (1);
9435
9436                         if (sp [-1]->type == STACK_R8) {
9437                                 ADD_UNOP (CEE_CONV_OVF_I8);
9438                                 ADD_UNOP (*ip);
9439                         } else {
9440                                 ADD_UNOP (*ip);
9441                         }
9442                         ip++;
9443                         break;
9444                 case CEE_CONV_OVF_U1:
9445                 case CEE_CONV_OVF_U2:
9446                 case CEE_CONV_OVF_U4:
9447                         CHECK_STACK (1);
9448
9449                         if (sp [-1]->type == STACK_R8) {
9450                                 ADD_UNOP (CEE_CONV_OVF_U8);
9451                                 ADD_UNOP (*ip);
9452                         } else {
9453                                 ADD_UNOP (*ip);
9454                         }
9455                         ip++;
9456                         break;
9457                 case CEE_CONV_OVF_I1_UN:
9458                 case CEE_CONV_OVF_I2_UN:
9459                 case CEE_CONV_OVF_I4_UN:
9460                 case CEE_CONV_OVF_I8_UN:
9461                 case CEE_CONV_OVF_U1_UN:
9462                 case CEE_CONV_OVF_U2_UN:
9463                 case CEE_CONV_OVF_U4_UN:
9464                 case CEE_CONV_OVF_U8_UN:
9465                 case CEE_CONV_OVF_I_UN:
9466                 case CEE_CONV_OVF_U_UN:
9467                 case CEE_CONV_U2:
9468                 case CEE_CONV_U1:
9469                 case CEE_CONV_I:
9470                 case CEE_CONV_U:
9471                         CHECK_STACK (1);
9472                         ADD_UNOP (*ip);
9473                         CHECK_CFG_EXCEPTION;
9474                         ip++;
9475                         break;
9476                 case CEE_ADD_OVF:
9477                 case CEE_ADD_OVF_UN:
9478                 case CEE_MUL_OVF:
9479                 case CEE_MUL_OVF_UN:
9480                 case CEE_SUB_OVF:
9481                 case CEE_SUB_OVF_UN:
9482                         CHECK_STACK (2);
9483                         ADD_BINOP (*ip);
9484                         ip++;
9485                         break;
9486                 case CEE_CPOBJ:
9487                         GSHAREDVT_FAILURE (*ip);
9488                         CHECK_OPSIZE (5);
9489                         CHECK_STACK (2);
9490                         token = read32 (ip + 1);
9491                         klass = mini_get_class (method, token, generic_context);
9492                         CHECK_TYPELOAD (klass);
9493                         sp -= 2;
9494                         if (generic_class_is_reference_type (cfg, klass)) {
9495                                 MonoInst *store, *load;
9496                                 int dreg = alloc_ireg_ref (cfg);
9497
9498                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9499                                 load->flags |= ins_flag;
9500                                 MONO_ADD_INS (cfg->cbb, load);
9501
9502                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9503                                 store->flags |= ins_flag;
9504                                 MONO_ADD_INS (cfg->cbb, store);
9505
9506                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9507                                         emit_write_barrier (cfg, sp [0], sp [1]);
9508                         } else {
9509                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9510                         }
9511                         ins_flag = 0;
9512                         ip += 5;
9513                         break;
9514                 case CEE_LDOBJ: {
9515                         int loc_index = -1;
9516                         int stloc_len = 0;
9517
9518                         CHECK_OPSIZE (5);
9519                         CHECK_STACK (1);
9520                         --sp;
9521                         token = read32 (ip + 1);
9522                         klass = mini_get_class (method, token, generic_context);
9523                         CHECK_TYPELOAD (klass);
9524
9525                         /* Optimize the common ldobj+stloc combination */
9526                         switch (ip [5]) {
9527                         case CEE_STLOC_S:
9528                                 loc_index = ip [6];
9529                                 stloc_len = 2;
9530                                 break;
9531                         case CEE_STLOC_0:
9532                         case CEE_STLOC_1:
9533                         case CEE_STLOC_2:
9534                         case CEE_STLOC_3:
9535                                 loc_index = ip [5] - CEE_STLOC_0;
9536                                 stloc_len = 1;
9537                                 break;
9538                         default:
9539                                 break;
9540                         }
9541
9542                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9543                                 CHECK_LOCAL (loc_index);
9544
9545                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9546                                 ins->dreg = cfg->locals [loc_index]->dreg;
9547                                 ins->flags |= ins_flag;
9548                                 ip += 5;
9549                                 ip += stloc_len;
9550                                 if (ins_flag & MONO_INST_VOLATILE) {
9551                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9552                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9553                                         emit_memory_barrier (cfg, FullBarrier);
9554                                 }
9555                                 ins_flag = 0;
9556                                 break;
9557                         }
9558
9559                         /* Optimize the ldobj+stobj combination */
9560                         /* The reference case ends up being a load+store anyway */
9561                         /* Skip this if the operation is volatile. */
9562                         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)) {
9563                                 CHECK_STACK (1);
9564
9565                                 sp --;
9566
9567                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9568
9569                                 ip += 5 + 5;
9570                                 ins_flag = 0;
9571                                 break;
9572                         }
9573
9574                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9575                         ins->flags |= ins_flag;
9576                         *sp++ = ins;
9577
9578                         if (ins_flag & MONO_INST_VOLATILE) {
9579                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9580                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9581                                 emit_memory_barrier (cfg, FullBarrier);
9582                         }
9583
9584                         ip += 5;
9585                         ins_flag = 0;
9586                         inline_costs += 1;
9587                         break;
9588                 }
9589                 case CEE_LDSTR:
9590                         CHECK_STACK_OVF (1);
9591                         CHECK_OPSIZE (5);
9592                         n = read32 (ip + 1);
9593
9594                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9595                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9596                                 ins->type = STACK_OBJ;
9597                                 *sp = ins;
9598                         }
9599                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9600                                 MonoInst *iargs [1];
9601
9602                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9603                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9604                         } else {
9605                                 if (cfg->opt & MONO_OPT_SHARED) {
9606                                         MonoInst *iargs [3];
9607
9608                                         if (cfg->compile_aot) {
9609                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9610                                         }
9611                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9612                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9613                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9614                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9615                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9616                                 } else {
9617                                         if (bblock->out_of_line) {
9618                                                 MonoInst *iargs [2];
9619
9620                                                 if (image == mono_defaults.corlib) {
9621                                                         /* 
9622                                                          * Avoid relocations in AOT and save some space by using a 
9623                                                          * version of helper_ldstr specialized to mscorlib.
9624                                                          */
9625                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9626                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9627                                                 } else {
9628                                                         /* Avoid creating the string object */
9629                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9630                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9631                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9632                                                 }
9633                                         } 
9634                                         else
9635                                         if (cfg->compile_aot) {
9636                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9637                                                 *sp = ins;
9638                                                 MONO_ADD_INS (bblock, ins);
9639                                         } 
9640                                         else {
9641                                                 NEW_PCONST (cfg, ins, NULL);
9642                                                 ins->type = STACK_OBJ;
9643                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9644                                                 if (!ins->inst_p0)
9645                                                         OUT_OF_MEMORY_FAILURE;
9646
9647                                                 *sp = ins;
9648                                                 MONO_ADD_INS (bblock, ins);
9649                                         }
9650                                 }
9651                         }
9652
9653                         sp++;
9654                         ip += 5;
9655                         break;
9656                 case CEE_NEWOBJ: {
9657                         MonoInst *iargs [2];
9658                         MonoMethodSignature *fsig;
9659                         MonoInst this_ins;
9660                         MonoInst *alloc;
9661                         MonoInst *vtable_arg = NULL;
9662
9663                         CHECK_OPSIZE (5);
9664                         token = read32 (ip + 1);
9665                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9666                         if (!cmethod || mono_loader_get_last_error ())
9667                                 LOAD_ERROR;
9668                         fsig = mono_method_get_signature (cmethod, image, token);
9669                         if (!fsig)
9670                                 LOAD_ERROR;
9671
9672                         mono_save_token_info (cfg, image, token, cmethod);
9673
9674                         if (!mono_class_init (cmethod->klass))
9675                                 TYPE_LOAD_ERROR (cmethod->klass);
9676
9677                         context_used = mini_method_check_context_used (cfg, cmethod);
9678
9679                         if (mono_security_cas_enabled ()) {
9680                                 if (check_linkdemand (cfg, method, cmethod))
9681                                         INLINE_FAILURE ("linkdemand");
9682                                 CHECK_CFG_EXCEPTION;
9683                         } else if (mono_security_core_clr_enabled ()) {
9684                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9685                         }
9686
9687                         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)) {
9688                                 emit_generic_class_init (cfg, cmethod->klass);
9689                                 CHECK_TYPELOAD (cmethod->klass);
9690                         }
9691
9692                         /*
9693                         if (cfg->gsharedvt) {
9694                                 if (mini_is_gsharedvt_variable_signature (sig))
9695                                         GSHAREDVT_FAILURE (*ip);
9696                         }
9697                         */
9698
9699                         n = fsig->param_count;
9700                         CHECK_STACK (n);
9701
9702                         /* 
9703                          * Generate smaller code for the common newobj <exception> instruction in
9704                          * argument checking code.
9705                          */
9706                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9707                                 is_exception_class (cmethod->klass) && n <= 2 &&
9708                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9709                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9710                                 MonoInst *iargs [3];
9711
9712                                 sp -= n;
9713
9714                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9715                                 switch (n) {
9716                                 case 0:
9717                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9718                                         break;
9719                                 case 1:
9720                                         iargs [1] = sp [0];
9721                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9722                                         break;
9723                                 case 2:
9724                                         iargs [1] = sp [0];
9725                                         iargs [2] = sp [1];
9726                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9727                                         break;
9728                                 default:
9729                                         g_assert_not_reached ();
9730                                 }
9731
9732                                 ip += 5;
9733                                 inline_costs += 5;
9734                                 break;
9735                         }
9736
9737                         /* move the args to allow room for 'this' in the first position */
9738                         while (n--) {
9739                                 --sp;
9740                                 sp [1] = sp [0];
9741                         }
9742
9743                         /* check_call_signature () requires sp[0] to be set */
9744                         this_ins.type = STACK_OBJ;
9745                         sp [0] = &this_ins;
9746                         if (check_call_signature (cfg, fsig, sp))
9747                                 UNVERIFIED;
9748
9749                         iargs [0] = NULL;
9750
9751                         if (mini_class_is_system_array (cmethod->klass)) {
9752                                 *sp = emit_get_rgctx_method (cfg, context_used,
9753                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9754
9755                                 /* Avoid varargs in the common case */
9756                                 if (fsig->param_count == 1)
9757                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9758                                 else if (fsig->param_count == 2)
9759                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9760                                 else if (fsig->param_count == 3)
9761                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9762                                 else if (fsig->param_count == 4)
9763                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9764                                 else
9765                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9766                         } else if (cmethod->string_ctor) {
9767                                 g_assert (!context_used);
9768                                 g_assert (!vtable_arg);
9769                                 /* we simply pass a null pointer */
9770                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9771                                 /* now call the string ctor */
9772                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9773                         } else {
9774                                 if (cmethod->klass->valuetype) {
9775                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9776                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9777                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9778
9779                                         alloc = NULL;
9780
9781                                         /* 
9782                                          * The code generated by mini_emit_virtual_call () expects
9783                                          * iargs [0] to be a boxed instance, but luckily the vcall
9784                                          * will be transformed into a normal call there.
9785                                          */
9786                                 } else if (context_used) {
9787                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9788                                         *sp = alloc;
9789                                 } else {
9790                                         MonoVTable *vtable = NULL;
9791
9792                                         if (!cfg->compile_aot)
9793                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9794                                         CHECK_TYPELOAD (cmethod->klass);
9795
9796                                         /*
9797                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9798                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9799                                          * As a workaround, we call class cctors before allocating objects.
9800                                          */
9801                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9802                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9803                                                 if (cfg->verbose_level > 2)
9804                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9805                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9806                                         }
9807
9808                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9809                                         *sp = alloc;
9810                                 }
9811                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9812
9813                                 if (alloc)
9814                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9815
9816                                 /* Now call the actual ctor */
9817                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
9818                                 CHECK_CFG_EXCEPTION;
9819                         }
9820
9821                         if (alloc == NULL) {
9822                                 /* Valuetype */
9823                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9824                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9825                                 *sp++= ins;
9826                         } else {
9827                                 *sp++ = alloc;
9828                         }
9829                         
9830                         ip += 5;
9831                         inline_costs += 5;
9832                         break;
9833                 }
9834                 case CEE_CASTCLASS:
9835                         CHECK_STACK (1);
9836                         --sp;
9837                         CHECK_OPSIZE (5);
9838                         token = read32 (ip + 1);
9839                         klass = mini_get_class (method, token, generic_context);
9840                         CHECK_TYPELOAD (klass);
9841                         if (sp [0]->type != STACK_OBJ)
9842                                 UNVERIFIED;
9843
9844                         context_used = mini_class_check_context_used (cfg, klass);
9845
9846                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9847                                 *sp = emit_castclass_with_cache_nonshared (cfg, sp [0], klass, &bblock);
9848                                 sp ++;
9849                                 ip += 5;
9850                                 inline_costs += 2;
9851                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9852                                 MonoMethod *mono_castclass;
9853                                 MonoInst *iargs [1];
9854                                 int costs;
9855
9856                                 mono_castclass = mono_marshal_get_castclass (klass); 
9857                                 iargs [0] = sp [0];
9858                                 
9859                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9860                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9861                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
9862                                 reset_cast_details (cfg);
9863                                 CHECK_CFG_EXCEPTION;
9864                                 g_assert (costs > 0);
9865                                 
9866                                 ip += 5;
9867                                 cfg->real_offset += 5;
9868
9869                                 *sp++ = iargs [0];
9870
9871                                 inline_costs += costs;
9872                         }
9873                         else {
9874                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9875                                 CHECK_CFG_EXCEPTION;
9876                                 bblock = cfg->cbb;
9877                                 *sp ++ = ins;
9878                                 ip += 5;
9879                         }
9880                         break;
9881                 case CEE_ISINST: {
9882                         CHECK_STACK (1);
9883                         --sp;
9884                         CHECK_OPSIZE (5);
9885                         token = read32 (ip + 1);
9886                         klass = mini_get_class (method, token, generic_context);
9887                         CHECK_TYPELOAD (klass);
9888                         if (sp [0]->type != STACK_OBJ)
9889                                 UNVERIFIED;
9890  
9891                         context_used = mini_class_check_context_used (cfg, klass);
9892
9893                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9894                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9895                                 MonoInst *args [3];
9896
9897                                 /* obj */
9898                                 args [0] = *sp;
9899
9900                                 /* klass */
9901                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9902
9903                                 /* inline cache*/
9904                                 if (cfg->compile_aot)
9905                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9906                                 else
9907                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9908
9909                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9910                                 ip += 5;
9911                                 inline_costs += 2;
9912                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9913                                 MonoMethod *mono_isinst;
9914                                 MonoInst *iargs [1];
9915                                 int costs;
9916
9917                                 mono_isinst = mono_marshal_get_isinst (klass); 
9918                                 iargs [0] = sp [0];
9919
9920                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9921                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
9922                                 CHECK_CFG_EXCEPTION;
9923                                 g_assert (costs > 0);
9924                                 
9925                                 ip += 5;
9926                                 cfg->real_offset += 5;
9927
9928                                 *sp++= iargs [0];
9929
9930                                 inline_costs += costs;
9931                         }
9932                         else {
9933                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9934                                 CHECK_CFG_EXCEPTION;
9935                                 bblock = cfg->cbb;
9936                                 *sp ++ = ins;
9937                                 ip += 5;
9938                         }
9939                         break;
9940                 }
9941                 case CEE_UNBOX_ANY: {
9942                         CHECK_STACK (1);
9943                         --sp;
9944                         CHECK_OPSIZE (5);
9945                         token = read32 (ip + 1);
9946                         klass = mini_get_class (method, token, generic_context);
9947                         CHECK_TYPELOAD (klass);
9948  
9949                         mono_save_token_info (cfg, image, token, klass);
9950
9951                         context_used = mini_class_check_context_used (cfg, klass);
9952
9953                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9954                                 *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9955                                 sp ++;
9956
9957                                 ip += 5;
9958                                 inline_costs += 2;
9959                                 break;
9960                         }
9961
9962                         if (generic_class_is_reference_type (cfg, klass)) {
9963                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9964                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9965                                         *sp = emit_castclass_with_cache_nonshared (cfg, sp [0], klass, &bblock);
9966                                         sp ++;
9967                                         ip += 5;
9968                                         inline_costs += 2;
9969                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9970                                         MonoMethod *mono_castclass;
9971                                         MonoInst *iargs [1];
9972                                         int costs;
9973
9974                                         mono_castclass = mono_marshal_get_castclass (klass); 
9975                                         iargs [0] = sp [0];
9976
9977                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9978                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
9979                                         CHECK_CFG_EXCEPTION;
9980                                         g_assert (costs > 0);
9981                                 
9982                                         ip += 5;
9983                                         cfg->real_offset += 5;
9984
9985                                         *sp++ = iargs [0];
9986                                         inline_costs += costs;
9987                                 } else {
9988                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9989                                         CHECK_CFG_EXCEPTION;
9990                                         bblock = cfg->cbb;
9991                                         *sp ++ = ins;
9992                                         ip += 5;
9993                                 }
9994                                 break;
9995                         }
9996
9997                         if (mono_class_is_nullable (klass)) {
9998                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9999                                 *sp++= ins;
10000                                 ip += 5;
10001                                 break;
10002                         }
10003
10004                         /* UNBOX */
10005                         ins = handle_unbox (cfg, klass, sp, context_used);
10006                         *sp = ins;
10007
10008                         ip += 5;
10009
10010                         /* LDOBJ */
10011                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10012                         *sp++ = ins;
10013
10014                         inline_costs += 2;
10015                         break;
10016                 }
10017                 case CEE_BOX: {
10018                         MonoInst *val;
10019
10020                         CHECK_STACK (1);
10021                         --sp;
10022                         val = *sp;
10023                         CHECK_OPSIZE (5);
10024                         token = read32 (ip + 1);
10025                         klass = mini_get_class (method, token, generic_context);
10026                         CHECK_TYPELOAD (klass);
10027
10028                         mono_save_token_info (cfg, image, token, klass);
10029
10030                         context_used = mini_class_check_context_used (cfg, klass);
10031
10032                         if (generic_class_is_reference_type (cfg, klass)) {
10033                                 *sp++ = val;
10034                                 ip += 5;
10035                                 break;
10036                         }
10037
10038                         if (klass == mono_defaults.void_class)
10039                                 UNVERIFIED;
10040                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10041                                 UNVERIFIED;
10042                         /* frequent check in generic code: box (struct), brtrue */
10043
10044                         // FIXME: LLVM can't handle the inconsistent bb linking
10045                         if (!mono_class_is_nullable (klass) &&
10046                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
10047                                 (ip [5] == CEE_BRTRUE || 
10048                                  ip [5] == CEE_BRTRUE_S ||
10049                                  ip [5] == CEE_BRFALSE ||
10050                                  ip [5] == CEE_BRFALSE_S)) {
10051                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10052                                 int dreg;
10053                                 MonoBasicBlock *true_bb, *false_bb;
10054
10055                                 ip += 5;
10056
10057                                 if (cfg->verbose_level > 3) {
10058                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10059                                         printf ("<box+brtrue opt>\n");
10060                                 }
10061
10062                                 switch (*ip) {
10063                                 case CEE_BRTRUE_S:
10064                                 case CEE_BRFALSE_S:
10065                                         CHECK_OPSIZE (2);
10066                                         ip++;
10067                                         target = ip + 1 + (signed char)(*ip);
10068                                         ip++;
10069                                         break;
10070                                 case CEE_BRTRUE:
10071                                 case CEE_BRFALSE:
10072                                         CHECK_OPSIZE (5);
10073                                         ip++;
10074                                         target = ip + 4 + (gint)(read32 (ip));
10075                                         ip += 4;
10076                                         break;
10077                                 default:
10078                                         g_assert_not_reached ();
10079                                 }
10080
10081                                 /* 
10082                                  * We need to link both bblocks, since it is needed for handling stack
10083                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10084                                  * Branching to only one of them would lead to inconsistencies, so
10085                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10086                                  */
10087                                 GET_BBLOCK (cfg, true_bb, target);
10088                                 GET_BBLOCK (cfg, false_bb, ip);
10089
10090                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10091                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10092
10093                                 if (sp != stack_start) {
10094                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10095                                         sp = stack_start;
10096                                         CHECK_UNVERIFIABLE (cfg);
10097                                 }
10098
10099                                 if (COMPILE_LLVM (cfg)) {
10100                                         dreg = alloc_ireg (cfg);
10101                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10102                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10103
10104                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10105                                 } else {
10106                                         /* The JIT can't eliminate the iconst+compare */
10107                                         MONO_INST_NEW (cfg, ins, OP_BR);
10108                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10109                                         MONO_ADD_INS (cfg->cbb, ins);
10110                                 }
10111
10112                                 start_new_bblock = 1;
10113                                 break;
10114                         }
10115
10116                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10117
10118                         CHECK_CFG_EXCEPTION;
10119                         ip += 5;
10120                         inline_costs += 1;
10121                         break;
10122                 }
10123                 case CEE_UNBOX: {
10124                         CHECK_STACK (1);
10125                         --sp;
10126                         CHECK_OPSIZE (5);
10127                         token = read32 (ip + 1);
10128                         klass = mini_get_class (method, token, generic_context);
10129                         CHECK_TYPELOAD (klass);
10130
10131                         mono_save_token_info (cfg, image, token, klass);
10132
10133                         context_used = mini_class_check_context_used (cfg, klass);
10134
10135                         if (mono_class_is_nullable (klass)) {
10136                                 MonoInst *val;
10137
10138                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10139                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10140
10141                                 *sp++= ins;
10142                         } else {
10143                                 ins = handle_unbox (cfg, klass, sp, context_used);
10144                                 *sp++ = ins;
10145                         }
10146                         ip += 5;
10147                         inline_costs += 2;
10148                         break;
10149                 }
10150                 case CEE_LDFLD:
10151                 case CEE_LDFLDA:
10152                 case CEE_STFLD:
10153                 case CEE_LDSFLD:
10154                 case CEE_LDSFLDA:
10155                 case CEE_STSFLD: {
10156                         MonoClassField *field;
10157 #ifndef DISABLE_REMOTING
10158                         int costs;
10159 #endif
10160                         guint foffset;
10161                         gboolean is_instance;
10162                         int op;
10163                         gpointer addr = NULL;
10164                         gboolean is_special_static;
10165                         MonoType *ftype;
10166                         MonoInst *store_val = NULL;
10167                         MonoInst *thread_ins;
10168
10169                         op = *ip;
10170                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10171                         if (is_instance) {
10172                                 if (op == CEE_STFLD) {
10173                                         CHECK_STACK (2);
10174                                         sp -= 2;
10175                                         store_val = sp [1];
10176                                 } else {
10177                                         CHECK_STACK (1);
10178                                         --sp;
10179                                 }
10180                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10181                                         UNVERIFIED;
10182                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10183                                         UNVERIFIED;
10184                         } else {
10185                                 if (op == CEE_STSFLD) {
10186                                         CHECK_STACK (1);
10187                                         sp--;
10188                                         store_val = sp [0];
10189                                 }
10190                         }
10191
10192                         CHECK_OPSIZE (5);
10193                         token = read32 (ip + 1);
10194                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10195                                 field = mono_method_get_wrapper_data (method, token);
10196                                 klass = field->parent;
10197                         }
10198                         else {
10199                                 field = mono_field_from_token (image, token, &klass, generic_context);
10200                         }
10201                         if (!field)
10202                                 LOAD_ERROR;
10203                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10204                                 FIELD_ACCESS_FAILURE (method, field);
10205                         mono_class_init (klass);
10206
10207                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10208                                 UNVERIFIED;
10209
10210                         /* if the class is Critical then transparent code cannot access it's fields */
10211                         if (!is_instance && mono_security_core_clr_enabled ())
10212                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10213
10214                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10215                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10216                         if (mono_security_core_clr_enabled ())
10217                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10218                         */
10219
10220                         /*
10221                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10222                          * the static case.
10223                          */
10224                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10225                                 switch (op) {
10226                                 case CEE_LDFLD:
10227                                         op = CEE_LDSFLD;
10228                                         break;
10229                                 case CEE_STFLD:
10230                                         op = CEE_STSFLD;
10231                                         break;
10232                                 case CEE_LDFLDA:
10233                                         op = CEE_LDSFLDA;
10234                                         break;
10235                                 default:
10236                                         g_assert_not_reached ();
10237                                 }
10238                                 is_instance = FALSE;
10239                         }
10240
10241                         context_used = mini_class_check_context_used (cfg, klass);
10242
10243                         /* INSTANCE CASE */
10244
10245                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10246                         if (op == CEE_STFLD) {
10247                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10248                                         UNVERIFIED;
10249 #ifndef DISABLE_REMOTING
10250                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10251                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10252                                         MonoInst *iargs [5];
10253
10254                                         GSHAREDVT_FAILURE (op);
10255
10256                                         iargs [0] = sp [0];
10257                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10258                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10259                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10260                                                     field->offset);
10261                                         iargs [4] = sp [1];
10262
10263                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10264                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10265                                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10266                                                 CHECK_CFG_EXCEPTION;
10267                                                 g_assert (costs > 0);
10268                                                       
10269                                                 cfg->real_offset += 5;
10270
10271                                                 inline_costs += costs;
10272                                         } else {
10273                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10274                                         }
10275                                 } else
10276 #endif
10277                                 {
10278                                         MonoInst *store;
10279
10280                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10281
10282                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10283                                                 MonoInst *offset_ins;
10284
10285                                                 context_used = mini_class_check_context_used (cfg, klass);
10286
10287                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10288                                                 dreg = alloc_ireg_mp (cfg);
10289                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10290                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10291                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10292                                         } else {
10293                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10294                                         }
10295                                         if (sp [0]->opcode != OP_LDADDR)
10296                                                 store->flags |= MONO_INST_FAULT;
10297
10298                                 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)) {
10299                                         /* insert call to write barrier */
10300                                         MonoInst *ptr;
10301                                         int dreg;
10302
10303                                         dreg = alloc_ireg_mp (cfg);
10304                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10305                                         emit_write_barrier (cfg, ptr, sp [1]);
10306                                 }
10307
10308                                         store->flags |= ins_flag;
10309                                 }
10310                                 ins_flag = 0;
10311                                 ip += 5;
10312                                 break;
10313                         }
10314
10315 #ifndef DISABLE_REMOTING
10316                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10317                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10318                                 MonoInst *iargs [4];
10319
10320                                 GSHAREDVT_FAILURE (op);
10321
10322                                 iargs [0] = sp [0];
10323                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10324                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10325                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10326                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10327                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10328                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
10329                                         CHECK_CFG_EXCEPTION;
10330                                         g_assert (costs > 0);
10331                                                       
10332                                         cfg->real_offset += 5;
10333
10334                                         *sp++ = iargs [0];
10335
10336                                         inline_costs += costs;
10337                                 } else {
10338                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10339                                         *sp++ = ins;
10340                                 }
10341                         } else 
10342 #endif
10343                         if (is_instance) {
10344                                 if (sp [0]->type == STACK_VTYPE) {
10345                                         MonoInst *var;
10346
10347                                         /* Have to compute the address of the variable */
10348
10349                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10350                                         if (!var)
10351                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10352                                         else
10353                                                 g_assert (var->klass == klass);
10354                                         
10355                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10356                                         sp [0] = ins;
10357                                 }
10358
10359                                 if (op == CEE_LDFLDA) {
10360                                         if (is_magic_tls_access (field)) {
10361                                                 GSHAREDVT_FAILURE (*ip);
10362                                                 ins = sp [0];
10363                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10364                                         } else {
10365                                                 if (sp [0]->type == STACK_OBJ) {
10366                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10367                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10368                                                 }
10369
10370                                                 dreg = alloc_ireg_mp (cfg);
10371
10372                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10373                                                         MonoInst *offset_ins;
10374
10375                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10376                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10377                                                 } else {
10378                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10379                                                 }
10380                                                 ins->klass = mono_class_from_mono_type (field->type);
10381                                                 ins->type = STACK_MP;
10382                                                 *sp++ = ins;
10383                                         }
10384                                 } else {
10385                                         MonoInst *load;
10386
10387                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10388
10389                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10390                                                 MonoInst *offset_ins;
10391
10392                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10393                                                 dreg = alloc_ireg_mp (cfg);
10394                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10395                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10396                                         } else {
10397                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10398                                         }
10399                                         load->flags |= ins_flag;
10400                                         if (sp [0]->opcode != OP_LDADDR)
10401                                                 load->flags |= MONO_INST_FAULT;
10402                                         *sp++ = load;
10403                                 }
10404                         }
10405
10406                         if (is_instance) {
10407                                 ins_flag = 0;
10408                                 ip += 5;
10409                                 break;
10410                         }
10411
10412                         /* STATIC CASE */
10413
10414                         /*
10415                          * We can only support shared generic static
10416                          * field access on architectures where the
10417                          * trampoline code has been extended to handle
10418                          * the generic class init.
10419                          */
10420 #ifndef MONO_ARCH_VTABLE_REG
10421                         GENERIC_SHARING_FAILURE (op);
10422 #endif
10423
10424                         context_used = mini_class_check_context_used (cfg, klass);
10425
10426                         ftype = mono_field_get_type (field);
10427
10428                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10429                                 UNVERIFIED;
10430
10431                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10432                          * to be called here.
10433                          */
10434                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10435                                 mono_class_vtable (cfg->domain, klass);
10436                                 CHECK_TYPELOAD (klass);
10437                         }
10438                         mono_domain_lock (cfg->domain);
10439                         if (cfg->domain->special_static_fields)
10440                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10441                         mono_domain_unlock (cfg->domain);
10442
10443                         is_special_static = mono_class_field_is_special_static (field);
10444
10445                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10446                                 thread_ins = mono_get_thread_intrinsic (cfg);
10447                         else
10448                                 thread_ins = NULL;
10449
10450                         /* Generate IR to compute the field address */
10451                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10452                                 /*
10453                                  * Fast access to TLS data
10454                                  * Inline version of get_thread_static_data () in
10455                                  * threads.c.
10456                                  */
10457                                 guint32 offset;
10458                                 int idx, static_data_reg, array_reg, dreg;
10459
10460                                 GSHAREDVT_FAILURE (op);
10461
10462                                 // offset &= 0x7fffffff;
10463                                 // idx = (offset >> 24) - 1;
10464                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10465                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10466                                 static_data_reg = alloc_ireg (cfg);
10467                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10468
10469                                 if (cfg->compile_aot) {
10470                                         int offset_reg, offset2_reg, idx_reg;
10471
10472                                         /* For TLS variables, this will return the TLS offset */
10473                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10474                                         offset_reg = ins->dreg;
10475                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10476                                         idx_reg = alloc_ireg (cfg);
10477                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10478                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10479                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10480                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10481                                         array_reg = alloc_ireg (cfg);
10482                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10483                                         offset2_reg = alloc_ireg (cfg);
10484                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10485                                         dreg = alloc_ireg (cfg);
10486                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10487                                 } else {
10488                                         offset = (gsize)addr & 0x7fffffff;
10489                                         idx = (offset >> 24) - 1;
10490
10491                                         array_reg = alloc_ireg (cfg);
10492                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10493                                         dreg = alloc_ireg (cfg);
10494                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10495                                 }
10496                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10497                                         (cfg->compile_aot && is_special_static) ||
10498                                         (context_used && is_special_static)) {
10499                                 MonoInst *iargs [2];
10500
10501                                 g_assert (field->parent);
10502                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10503                                 if (context_used) {
10504                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10505                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10506                                 } else {
10507                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10508                                 }
10509                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10510                         } else if (context_used) {
10511                                 MonoInst *static_data;
10512
10513                                 /*
10514                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10515                                         method->klass->name_space, method->klass->name, method->name,
10516                                         depth, field->offset);
10517                                 */
10518
10519                                 if (mono_class_needs_cctor_run (klass, method))
10520                                         emit_generic_class_init (cfg, klass);
10521
10522                                 /*
10523                                  * The pointer we're computing here is
10524                                  *
10525                                  *   super_info.static_data + field->offset
10526                                  */
10527                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10528                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10529
10530                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10531                                         MonoInst *offset_ins;
10532
10533                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10534                                         dreg = alloc_ireg_mp (cfg);
10535                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10536                                 } else if (field->offset == 0) {
10537                                         ins = static_data;
10538                                 } else {
10539                                         int addr_reg = mono_alloc_preg (cfg);
10540                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10541                                 }
10542                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10543                                 MonoInst *iargs [2];
10544
10545                                 g_assert (field->parent);
10546                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10547                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10548                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10549                         } else {
10550                                 MonoVTable *vtable = NULL;
10551
10552                                 if (!cfg->compile_aot)
10553                                         vtable = mono_class_vtable (cfg->domain, klass);
10554                                 CHECK_TYPELOAD (klass);
10555
10556                                 if (!addr) {
10557                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10558                                                 if (!(g_slist_find (class_inits, klass))) {
10559                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10560                                                         if (cfg->verbose_level > 2)
10561                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10562                                                         class_inits = g_slist_prepend (class_inits, klass);
10563                                                 }
10564                                         } else {
10565                                                 if (cfg->run_cctors) {
10566                                                         MonoException *ex;
10567                                                         /* This makes so that inline cannot trigger */
10568                                                         /* .cctors: too many apps depend on them */
10569                                                         /* running with a specific order... */
10570                                                         g_assert (vtable);
10571                                                         if (! vtable->initialized)
10572                                                                 INLINE_FAILURE ("class init");
10573                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10574                                                         if (ex) {
10575                                                                 set_exception_object (cfg, ex);
10576                                                                 goto exception_exit;
10577                                                         }
10578                                                 }
10579                                         }
10580                                         if (cfg->compile_aot)
10581                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10582                                         else {
10583                                                 g_assert (vtable);
10584                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10585                                                 g_assert (addr);
10586                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10587                                         }
10588                                 } else {
10589                                         MonoInst *iargs [1];
10590                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10591                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10592                                 }
10593                         }
10594
10595                         /* Generate IR to do the actual load/store operation */
10596
10597                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10598                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10599                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10600                                 emit_memory_barrier (cfg, FullBarrier);
10601                         }
10602
10603                         if (op == CEE_LDSFLDA) {
10604                                 ins->klass = mono_class_from_mono_type (ftype);
10605                                 ins->type = STACK_PTR;
10606                                 *sp++ = ins;
10607                         } else if (op == CEE_STSFLD) {
10608                                 MonoInst *store;
10609
10610                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10611                                 store->flags |= ins_flag;
10612                         } else {
10613                                 gboolean is_const = FALSE;
10614                                 MonoVTable *vtable = NULL;
10615                                 gpointer addr = NULL;
10616
10617                                 if (!context_used) {
10618                                         vtable = mono_class_vtable (cfg->domain, klass);
10619                                         CHECK_TYPELOAD (klass);
10620                                 }
10621                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10622                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10623                                         int ro_type = ftype->type;
10624                                         if (!addr)
10625                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10626                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10627                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10628                                         }
10629
10630                                         GSHAREDVT_FAILURE (op);
10631
10632                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10633                                         is_const = TRUE;
10634                                         switch (ro_type) {
10635                                         case MONO_TYPE_BOOLEAN:
10636                                         case MONO_TYPE_U1:
10637                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10638                                                 sp++;
10639                                                 break;
10640                                         case MONO_TYPE_I1:
10641                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10642                                                 sp++;
10643                                                 break;                                          
10644                                         case MONO_TYPE_CHAR:
10645                                         case MONO_TYPE_U2:
10646                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10647                                                 sp++;
10648                                                 break;
10649                                         case MONO_TYPE_I2:
10650                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10651                                                 sp++;
10652                                                 break;
10653                                                 break;
10654                                         case MONO_TYPE_I4:
10655                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10656                                                 sp++;
10657                                                 break;                                          
10658                                         case MONO_TYPE_U4:
10659                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10660                                                 sp++;
10661                                                 break;
10662                                         case MONO_TYPE_I:
10663                                         case MONO_TYPE_U:
10664                                         case MONO_TYPE_PTR:
10665                                         case MONO_TYPE_FNPTR:
10666                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10667                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10668                                                 sp++;
10669                                                 break;
10670                                         case MONO_TYPE_STRING:
10671                                         case MONO_TYPE_OBJECT:
10672                                         case MONO_TYPE_CLASS:
10673                                         case MONO_TYPE_SZARRAY:
10674                                         case MONO_TYPE_ARRAY:
10675                                                 if (!mono_gc_is_moving ()) {
10676                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10677                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10678                                                         sp++;
10679                                                 } else {
10680                                                         is_const = FALSE;
10681                                                 }
10682                                                 break;
10683                                         case MONO_TYPE_I8:
10684                                         case MONO_TYPE_U8:
10685                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10686                                                 sp++;
10687                                                 break;
10688                                         case MONO_TYPE_R4:
10689                                         case MONO_TYPE_R8:
10690                                         case MONO_TYPE_VALUETYPE:
10691                                         default:
10692                                                 is_const = FALSE;
10693                                                 break;
10694                                         }
10695                                 }
10696
10697                                 if (!is_const) {
10698                                         MonoInst *load;
10699
10700                                         CHECK_STACK_OVF (1);
10701
10702                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10703                                         load->flags |= ins_flag;
10704                                         ins_flag = 0;
10705                                         *sp++ = load;
10706                                 }
10707                         }
10708
10709                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10710                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10711                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10712                                 emit_memory_barrier (cfg, FullBarrier);
10713                         }
10714
10715                         ins_flag = 0;
10716                         ip += 5;
10717                         break;
10718                 }
10719                 case CEE_STOBJ:
10720                         CHECK_STACK (2);
10721                         sp -= 2;
10722                         CHECK_OPSIZE (5);
10723                         token = read32 (ip + 1);
10724                         klass = mini_get_class (method, token, generic_context);
10725                         CHECK_TYPELOAD (klass);
10726                         if (ins_flag & MONO_INST_VOLATILE) {
10727                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10728                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10729                                 emit_memory_barrier (cfg, FullBarrier);
10730                         }
10731                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10732                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10733                         ins->flags |= ins_flag;
10734                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10735                                         generic_class_is_reference_type (cfg, klass)) {
10736                                 /* insert call to write barrier */
10737                                 emit_write_barrier (cfg, sp [0], sp [1]);
10738                         }
10739                         ins_flag = 0;
10740                         ip += 5;
10741                         inline_costs += 1;
10742                         break;
10743
10744                         /*
10745                          * Array opcodes
10746                          */
10747                 case CEE_NEWARR: {
10748                         MonoInst *len_ins;
10749                         const char *data_ptr;
10750                         int data_size = 0;
10751                         guint32 field_token;
10752
10753                         CHECK_STACK (1);
10754                         --sp;
10755
10756                         CHECK_OPSIZE (5);
10757                         token = read32 (ip + 1);
10758
10759                         klass = mini_get_class (method, token, generic_context);
10760                         CHECK_TYPELOAD (klass);
10761
10762                         context_used = mini_class_check_context_used (cfg, klass);
10763
10764                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10765                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10766                                 ins->sreg1 = sp [0]->dreg;
10767                                 ins->type = STACK_I4;
10768                                 ins->dreg = alloc_ireg (cfg);
10769                                 MONO_ADD_INS (cfg->cbb, ins);
10770                                 *sp = mono_decompose_opcode (cfg, ins);
10771                         }
10772
10773                         if (context_used) {
10774                                 MonoInst *args [3];
10775                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10776                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10777
10778                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10779
10780                                 /* vtable */
10781                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10782                                         array_class, MONO_RGCTX_INFO_VTABLE);
10783                                 /* array len */
10784                                 args [1] = sp [0];
10785
10786                                 if (managed_alloc)
10787                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10788                                 else
10789                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10790                         } else {
10791                                 if (cfg->opt & MONO_OPT_SHARED) {
10792                                         /* Decompose now to avoid problems with references to the domainvar */
10793                                         MonoInst *iargs [3];
10794
10795                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10796                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10797                                         iargs [2] = sp [0];
10798
10799                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10800                                 } else {
10801                                         /* Decompose later since it is needed by abcrem */
10802                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10803                                         mono_class_vtable (cfg->domain, array_type);
10804                                         CHECK_TYPELOAD (array_type);
10805
10806                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10807                                         ins->dreg = alloc_ireg_ref (cfg);
10808                                         ins->sreg1 = sp [0]->dreg;
10809                                         ins->inst_newa_class = klass;
10810                                         ins->type = STACK_OBJ;
10811                                         ins->klass = array_type;
10812                                         MONO_ADD_INS (cfg->cbb, ins);
10813                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10814                                         cfg->cbb->has_array_access = TRUE;
10815
10816                                         /* Needed so mono_emit_load_get_addr () gets called */
10817                                         mono_get_got_var (cfg);
10818                                 }
10819                         }
10820
10821                         len_ins = sp [0];
10822                         ip += 5;
10823                         *sp++ = ins;
10824                         inline_costs += 1;
10825
10826                         /* 
10827                          * we inline/optimize the initialization sequence if possible.
10828                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10829                          * for small sizes open code the memcpy
10830                          * ensure the rva field is big enough
10831                          */
10832                         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))) {
10833                                 MonoMethod *memcpy_method = get_memcpy_method ();
10834                                 MonoInst *iargs [3];
10835                                 int add_reg = alloc_ireg_mp (cfg);
10836
10837                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
10838                                 if (cfg->compile_aot) {
10839                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10840                                 } else {
10841                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10842                                 }
10843                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10844                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10845                                 ip += 11;
10846                         }
10847
10848                         break;
10849                 }
10850                 case CEE_LDLEN:
10851                         CHECK_STACK (1);
10852                         --sp;
10853                         if (sp [0]->type != STACK_OBJ)
10854                                 UNVERIFIED;
10855
10856                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10857                         ins->dreg = alloc_preg (cfg);
10858                         ins->sreg1 = sp [0]->dreg;
10859                         ins->type = STACK_I4;
10860                         /* This flag will be inherited by the decomposition */
10861                         ins->flags |= MONO_INST_FAULT;
10862                         MONO_ADD_INS (cfg->cbb, ins);
10863                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10864                         cfg->cbb->has_array_access = TRUE;
10865                         ip ++;
10866                         *sp++ = ins;
10867                         break;
10868                 case CEE_LDELEMA:
10869                         CHECK_STACK (2);
10870                         sp -= 2;
10871                         CHECK_OPSIZE (5);
10872                         if (sp [0]->type != STACK_OBJ)
10873                                 UNVERIFIED;
10874
10875                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10876
10877                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10878                         CHECK_TYPELOAD (klass);
10879                         /* we need to make sure that this array is exactly the type it needs
10880                          * to be for correctness. the wrappers are lax with their usage
10881                          * so we need to ignore them here
10882                          */
10883                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10884                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10885                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10886                                 CHECK_TYPELOAD (array_class);
10887                         }
10888
10889                         readonly = FALSE;
10890                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10891                         *sp++ = ins;
10892                         ip += 5;
10893                         break;
10894                 case CEE_LDELEM:
10895                 case CEE_LDELEM_I1:
10896                 case CEE_LDELEM_U1:
10897                 case CEE_LDELEM_I2:
10898                 case CEE_LDELEM_U2:
10899                 case CEE_LDELEM_I4:
10900                 case CEE_LDELEM_U4:
10901                 case CEE_LDELEM_I8:
10902                 case CEE_LDELEM_I:
10903                 case CEE_LDELEM_R4:
10904                 case CEE_LDELEM_R8:
10905                 case CEE_LDELEM_REF: {
10906                         MonoInst *addr;
10907
10908                         CHECK_STACK (2);
10909                         sp -= 2;
10910
10911                         if (*ip == CEE_LDELEM) {
10912                                 CHECK_OPSIZE (5);
10913                                 token = read32 (ip + 1);
10914                                 klass = mini_get_class (method, token, generic_context);
10915                                 CHECK_TYPELOAD (klass);
10916                                 mono_class_init (klass);
10917                         }
10918                         else
10919                                 klass = array_access_to_klass (*ip);
10920
10921                         if (sp [0]->type != STACK_OBJ)
10922                                 UNVERIFIED;
10923
10924                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10925
10926                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
10927                                 // FIXME-VT: OP_ICONST optimization
10928                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10929                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10930                                 ins->opcode = OP_LOADV_MEMBASE;
10931                         } else if (sp [1]->opcode == OP_ICONST) {
10932                                 int array_reg = sp [0]->dreg;
10933                                 int index_reg = sp [1]->dreg;
10934                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
10935
10936                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10937                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10938                         } else {
10939                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10940                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10941                         }
10942                         *sp++ = ins;
10943                         if (*ip == CEE_LDELEM)
10944                                 ip += 5;
10945                         else
10946                                 ++ip;
10947                         break;
10948                 }
10949                 case CEE_STELEM_I:
10950                 case CEE_STELEM_I1:
10951                 case CEE_STELEM_I2:
10952                 case CEE_STELEM_I4:
10953                 case CEE_STELEM_I8:
10954                 case CEE_STELEM_R4:
10955                 case CEE_STELEM_R8:
10956                 case CEE_STELEM_REF:
10957                 case CEE_STELEM: {
10958                         CHECK_STACK (3);
10959                         sp -= 3;
10960
10961                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10962
10963                         if (*ip == CEE_STELEM) {
10964                                 CHECK_OPSIZE (5);
10965                                 token = read32 (ip + 1);
10966                                 klass = mini_get_class (method, token, generic_context);
10967                                 CHECK_TYPELOAD (klass);
10968                                 mono_class_init (klass);
10969                         }
10970                         else
10971                                 klass = array_access_to_klass (*ip);
10972
10973                         if (sp [0]->type != STACK_OBJ)
10974                                 UNVERIFIED;
10975
10976                         emit_array_store (cfg, klass, sp, TRUE);
10977
10978                         if (*ip == CEE_STELEM)
10979                                 ip += 5;
10980                         else
10981                                 ++ip;
10982                         inline_costs += 1;
10983                         break;
10984                 }
10985                 case CEE_CKFINITE: {
10986                         CHECK_STACK (1);
10987                         --sp;
10988
10989                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10990                         ins->sreg1 = sp [0]->dreg;
10991                         ins->dreg = alloc_freg (cfg);
10992                         ins->type = STACK_R8;
10993                         MONO_ADD_INS (bblock, ins);
10994
10995                         *sp++ = mono_decompose_opcode (cfg, ins);
10996
10997                         ++ip;
10998                         break;
10999                 }
11000                 case CEE_REFANYVAL: {
11001                         MonoInst *src_var, *src;
11002
11003                         int klass_reg = alloc_preg (cfg);
11004                         int dreg = alloc_preg (cfg);
11005
11006                         GSHAREDVT_FAILURE (*ip);
11007
11008                         CHECK_STACK (1);
11009                         MONO_INST_NEW (cfg, ins, *ip);
11010                         --sp;
11011                         CHECK_OPSIZE (5);
11012                         klass = mono_class_get_and_inflate_typespec_checked (image, read32 (ip + 1), generic_context, &error);
11013                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
11014                         CHECK_TYPELOAD (klass);
11015                         mono_class_init (klass);
11016
11017                         context_used = mini_class_check_context_used (cfg, klass);
11018
11019                         // FIXME:
11020                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11021                         if (!src_var)
11022                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11023                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11024                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11025
11026                         if (context_used) {
11027                                 MonoInst *klass_ins;
11028
11029                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11030                                                 klass, MONO_RGCTX_INFO_KLASS);
11031
11032                                 // FIXME:
11033                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11034                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11035                         } else {
11036                                 mini_emit_class_check (cfg, klass_reg, klass);
11037                         }
11038                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11039                         ins->type = STACK_MP;
11040                         *sp++ = ins;
11041                         ip += 5;
11042                         break;
11043                 }
11044                 case CEE_MKREFANY: {
11045                         MonoInst *loc, *addr;
11046
11047                         GSHAREDVT_FAILURE (*ip);
11048
11049                         CHECK_STACK (1);
11050                         MONO_INST_NEW (cfg, ins, *ip);
11051                         --sp;
11052                         CHECK_OPSIZE (5);
11053                         klass = mono_class_get_and_inflate_typespec_checked (image, read32 (ip + 1), generic_context, &error);
11054                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
11055                         CHECK_TYPELOAD (klass);
11056                         mono_class_init (klass);
11057
11058                         context_used = mini_class_check_context_used (cfg, klass);
11059
11060                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11061                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11062
11063                         if (context_used) {
11064                                 MonoInst *const_ins;
11065                                 int type_reg = alloc_preg (cfg);
11066
11067                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11068                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11069                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11070                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11071                         } else if (cfg->compile_aot) {
11072                                 int const_reg = alloc_preg (cfg);
11073                                 int type_reg = alloc_preg (cfg);
11074
11075                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11076                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11077                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11078                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11079                         } else {
11080                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11081                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11082                         }
11083                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11084
11085                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11086                         ins->type = STACK_VTYPE;
11087                         ins->klass = mono_defaults.typed_reference_class;
11088                         *sp++ = ins;
11089                         ip += 5;
11090                         break;
11091                 }
11092                 case CEE_LDTOKEN: {
11093                         gpointer handle;
11094                         MonoClass *handle_class;
11095
11096                         CHECK_STACK_OVF (1);
11097
11098                         CHECK_OPSIZE (5);
11099                         n = read32 (ip + 1);
11100
11101                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11102                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11103                                 handle = mono_method_get_wrapper_data (method, n);
11104                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11105                                 if (handle_class == mono_defaults.typehandle_class)
11106                                         handle = &((MonoClass*)handle)->byval_arg;
11107                         }
11108                         else {
11109                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
11110                         }
11111                         if (!handle)
11112                                 LOAD_ERROR;
11113                         mono_class_init (handle_class);
11114                         if (cfg->generic_sharing_context) {
11115                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11116                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11117                                         /* This case handles ldtoken
11118                                            of an open type, like for
11119                                            typeof(Gen<>). */
11120                                         context_used = 0;
11121                                 } else if (handle_class == mono_defaults.typehandle_class) {
11122                                         /* If we get a MONO_TYPE_CLASS
11123                                            then we need to provide the
11124                                            open type, not an
11125                                            instantiation of it. */
11126                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
11127                                                 context_used = 0;
11128                                         else
11129                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11130                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11131                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11132                                 else if (handle_class == mono_defaults.methodhandle_class)
11133                                         context_used = mini_method_check_context_used (cfg, handle);
11134                                 else
11135                                         g_assert_not_reached ();
11136                         }
11137
11138                         if ((cfg->opt & MONO_OPT_SHARED) &&
11139                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11140                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11141                                 MonoInst *addr, *vtvar, *iargs [3];
11142                                 int method_context_used;
11143
11144                                 method_context_used = mini_method_check_context_used (cfg, method);
11145
11146                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11147
11148                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11149                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11150                                 if (method_context_used) {
11151                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11152                                                 method, MONO_RGCTX_INFO_METHOD);
11153                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11154                                 } else {
11155                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11156                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11157                                 }
11158                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11159
11160                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11161
11162                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11163                         } else {
11164                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11165                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11166                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11167                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11168                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11169                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11170
11171                                         mono_class_init (tclass);
11172                                         if (context_used) {
11173                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11174                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11175                                         } else if (cfg->compile_aot) {
11176                                                 if (method->wrapper_type) {
11177                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11178                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11179                                                                 /* Special case for static synchronized wrappers */
11180                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11181                                                         } else {
11182                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11183                                                                 /* FIXME: n is not a normal token */
11184                                                                 DISABLE_AOT (cfg);
11185                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11186                                                         }
11187                                                 } else {
11188                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11189                                                 }
11190                                         } else {
11191                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11192                                         }
11193                                         ins->type = STACK_OBJ;
11194                                         ins->klass = cmethod->klass;
11195                                         ip += 5;
11196                                 } else {
11197                                         MonoInst *addr, *vtvar;
11198
11199                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11200
11201                                         if (context_used) {
11202                                                 if (handle_class == mono_defaults.typehandle_class) {
11203                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11204                                                                         mono_class_from_mono_type (handle),
11205                                                                         MONO_RGCTX_INFO_TYPE);
11206                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11207                                                         ins = emit_get_rgctx_method (cfg, context_used,
11208                                                                         handle, MONO_RGCTX_INFO_METHOD);
11209                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11210                                                         ins = emit_get_rgctx_field (cfg, context_used,
11211                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11212                                                 } else {
11213                                                         g_assert_not_reached ();
11214                                                 }
11215                                         } else if (cfg->compile_aot) {
11216                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11217                                         } else {
11218                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11219                                         }
11220                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11221                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11222                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11223                                 }
11224                         }
11225
11226                         *sp++ = ins;
11227                         ip += 5;
11228                         break;
11229                 }
11230                 case CEE_THROW:
11231                         CHECK_STACK (1);
11232                         MONO_INST_NEW (cfg, ins, OP_THROW);
11233                         --sp;
11234                         ins->sreg1 = sp [0]->dreg;
11235                         ip++;
11236                         bblock->out_of_line = TRUE;
11237                         MONO_ADD_INS (bblock, ins);
11238                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11239                         MONO_ADD_INS (bblock, ins);
11240                         sp = stack_start;
11241                         
11242                         link_bblock (cfg, bblock, end_bblock);
11243                         start_new_bblock = 1;
11244                         break;
11245                 case CEE_ENDFINALLY:
11246                         /* mono_save_seq_point_info () depends on this */
11247                         if (sp != stack_start)
11248                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11249                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11250                         MONO_ADD_INS (bblock, ins);
11251                         ip++;
11252                         start_new_bblock = 1;
11253
11254                         /*
11255                          * Control will leave the method so empty the stack, otherwise
11256                          * the next basic block will start with a nonempty stack.
11257                          */
11258                         while (sp != stack_start) {
11259                                 sp--;
11260                         }
11261                         break;
11262                 case CEE_LEAVE:
11263                 case CEE_LEAVE_S: {
11264                         GList *handlers;
11265
11266                         if (*ip == CEE_LEAVE) {
11267                                 CHECK_OPSIZE (5);
11268                                 target = ip + 5 + (gint32)read32(ip + 1);
11269                         } else {
11270                                 CHECK_OPSIZE (2);
11271                                 target = ip + 2 + (signed char)(ip [1]);
11272                         }
11273
11274                         /* empty the stack */
11275                         while (sp != stack_start) {
11276                                 sp--;
11277                         }
11278
11279                         /* 
11280                          * If this leave statement is in a catch block, check for a
11281                          * pending exception, and rethrow it if necessary.
11282                          * We avoid doing this in runtime invoke wrappers, since those are called
11283                          * by native code which excepts the wrapper to catch all exceptions.
11284                          */
11285                         for (i = 0; i < header->num_clauses; ++i) {
11286                                 MonoExceptionClause *clause = &header->clauses [i];
11287
11288                                 /* 
11289                                  * Use <= in the final comparison to handle clauses with multiple
11290                                  * leave statements, like in bug #78024.
11291                                  * The ordering of the exception clauses guarantees that we find the
11292                                  * innermost clause.
11293                                  */
11294                                 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) {
11295                                         MonoInst *exc_ins;
11296                                         MonoBasicBlock *dont_throw;
11297
11298                                         /*
11299                                           MonoInst *load;
11300
11301                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11302                                         */
11303
11304                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11305
11306                                         NEW_BBLOCK (cfg, dont_throw);
11307
11308                                         /*
11309                                          * Currently, we always rethrow the abort exception, despite the 
11310                                          * fact that this is not correct. See thread6.cs for an example. 
11311                                          * But propagating the abort exception is more important than 
11312                                          * getting the sematics right.
11313                                          */
11314                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11315                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11316                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11317
11318                                         MONO_START_BB (cfg, dont_throw);
11319                                         bblock = cfg->cbb;
11320                                 }
11321                         }
11322
11323                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11324                                 GList *tmp;
11325                                 MonoExceptionClause *clause;
11326
11327                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11328                                         clause = tmp->data;
11329                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11330                                         g_assert (tblock);
11331                                         link_bblock (cfg, bblock, tblock);
11332                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11333                                         ins->inst_target_bb = tblock;
11334                                         ins->inst_eh_block = clause;
11335                                         MONO_ADD_INS (bblock, ins);
11336                                         bblock->has_call_handler = 1;
11337                                         if (COMPILE_LLVM (cfg)) {
11338                                                 MonoBasicBlock *target_bb;
11339
11340                                                 /* 
11341                                                  * Link the finally bblock with the target, since it will
11342                                                  * conceptually branch there.
11343                                                  * FIXME: Have to link the bblock containing the endfinally.
11344                                                  */
11345                                                 GET_BBLOCK (cfg, target_bb, target);
11346                                                 link_bblock (cfg, tblock, target_bb);
11347                                         }
11348                                 }
11349                                 g_list_free (handlers);
11350                         } 
11351
11352                         MONO_INST_NEW (cfg, ins, OP_BR);
11353                         MONO_ADD_INS (bblock, ins);
11354                         GET_BBLOCK (cfg, tblock, target);
11355                         link_bblock (cfg, bblock, tblock);
11356                         ins->inst_target_bb = tblock;
11357                         start_new_bblock = 1;
11358
11359                         if (*ip == CEE_LEAVE)
11360                                 ip += 5;
11361                         else
11362                                 ip += 2;
11363
11364                         break;
11365                 }
11366
11367                         /*
11368                          * Mono specific opcodes
11369                          */
11370                 case MONO_CUSTOM_PREFIX: {
11371
11372                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11373
11374                         CHECK_OPSIZE (2);
11375                         switch (ip [1]) {
11376                         case CEE_MONO_ICALL: {
11377                                 gpointer func;
11378                                 MonoJitICallInfo *info;
11379
11380                                 token = read32 (ip + 2);
11381                                 func = mono_method_get_wrapper_data (method, token);
11382                                 info = mono_find_jit_icall_by_addr (func);
11383                                 if (!info)
11384                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11385                                 g_assert (info);
11386
11387                                 CHECK_STACK (info->sig->param_count);
11388                                 sp -= info->sig->param_count;
11389
11390                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11391                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11392                                         *sp++ = ins;
11393
11394                                 ip += 6;
11395                                 inline_costs += 10 * num_calls++;
11396
11397                                 break;
11398                         }
11399                         case CEE_MONO_LDPTR: {
11400                                 gpointer ptr;
11401
11402                                 CHECK_STACK_OVF (1);
11403                                 CHECK_OPSIZE (6);
11404                                 token = read32 (ip + 2);
11405
11406                                 ptr = mono_method_get_wrapper_data (method, token);
11407                                 /* FIXME: Generalize this */
11408                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11409                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11410                                         *sp++ = ins;
11411                                         ip += 6;
11412                                         break;
11413                                 }
11414                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11415                                 *sp++ = ins;
11416                                 ip += 6;
11417                                 inline_costs += 10 * num_calls++;
11418                                 /* Can't embed random pointers into AOT code */
11419                                 DISABLE_AOT (cfg);
11420                                 break;
11421                         }
11422                         case CEE_MONO_JIT_ICALL_ADDR: {
11423                                 MonoJitICallInfo *callinfo;
11424                                 gpointer ptr;
11425
11426                                 CHECK_STACK_OVF (1);
11427                                 CHECK_OPSIZE (6);
11428                                 token = read32 (ip + 2);
11429
11430                                 ptr = mono_method_get_wrapper_data (method, token);
11431                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11432                                 g_assert (callinfo);
11433                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11434                                 *sp++ = ins;
11435                                 ip += 6;
11436                                 inline_costs += 10 * num_calls++;
11437                                 break;
11438                         }
11439                         case CEE_MONO_ICALL_ADDR: {
11440                                 MonoMethod *cmethod;
11441                                 gpointer ptr;
11442
11443                                 CHECK_STACK_OVF (1);
11444                                 CHECK_OPSIZE (6);
11445                                 token = read32 (ip + 2);
11446
11447                                 cmethod = mono_method_get_wrapper_data (method, token);
11448
11449                                 if (cfg->compile_aot) {
11450                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11451                                 } else {
11452                                         ptr = mono_lookup_internal_call (cmethod);
11453                                         g_assert (ptr);
11454                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11455                                 }
11456                                 *sp++ = ins;
11457                                 ip += 6;
11458                                 break;
11459                         }
11460                         case CEE_MONO_VTADDR: {
11461                                 MonoInst *src_var, *src;
11462
11463                                 CHECK_STACK (1);
11464                                 --sp;
11465
11466                                 // FIXME:
11467                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11468                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11469                                 *sp++ = src;
11470                                 ip += 2;
11471                                 break;
11472                         }
11473                         case CEE_MONO_NEWOBJ: {
11474                                 MonoInst *iargs [2];
11475
11476                                 CHECK_STACK_OVF (1);
11477                                 CHECK_OPSIZE (6);
11478                                 token = read32 (ip + 2);
11479                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11480                                 mono_class_init (klass);
11481                                 NEW_DOMAINCONST (cfg, iargs [0]);
11482                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11483                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11484                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11485                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11486                                 ip += 6;
11487                                 inline_costs += 10 * num_calls++;
11488                                 break;
11489                         }
11490                         case CEE_MONO_OBJADDR:
11491                                 CHECK_STACK (1);
11492                                 --sp;
11493                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11494                                 ins->dreg = alloc_ireg_mp (cfg);
11495                                 ins->sreg1 = sp [0]->dreg;
11496                                 ins->type = STACK_MP;
11497                                 MONO_ADD_INS (cfg->cbb, ins);
11498                                 *sp++ = ins;
11499                                 ip += 2;
11500                                 break;
11501                         case CEE_MONO_LDNATIVEOBJ:
11502                                 /*
11503                                  * Similar to LDOBJ, but instead load the unmanaged 
11504                                  * representation of the vtype to the stack.
11505                                  */
11506                                 CHECK_STACK (1);
11507                                 CHECK_OPSIZE (6);
11508                                 --sp;
11509                                 token = read32 (ip + 2);
11510                                 klass = mono_method_get_wrapper_data (method, token);
11511                                 g_assert (klass->valuetype);
11512                                 mono_class_init (klass);
11513
11514                                 {
11515                                         MonoInst *src, *dest, *temp;
11516
11517                                         src = sp [0];
11518                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11519                                         temp->backend.is_pinvoke = 1;
11520                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11521                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11522
11523                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11524                                         dest->type = STACK_VTYPE;
11525                                         dest->klass = klass;
11526
11527                                         *sp ++ = dest;
11528                                         ip += 6;
11529                                 }
11530                                 break;
11531                         case CEE_MONO_RETOBJ: {
11532                                 /*
11533                                  * Same as RET, but return the native representation of a vtype
11534                                  * to the caller.
11535                                  */
11536                                 g_assert (cfg->ret);
11537                                 g_assert (mono_method_signature (method)->pinvoke); 
11538                                 CHECK_STACK (1);
11539                                 --sp;
11540                                 
11541                                 CHECK_OPSIZE (6);
11542                                 token = read32 (ip + 2);    
11543                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11544
11545                                 if (!cfg->vret_addr) {
11546                                         g_assert (cfg->ret_var_is_local);
11547
11548                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11549                                 } else {
11550                                         EMIT_NEW_RETLOADA (cfg, ins);
11551                                 }
11552                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11553                                 
11554                                 if (sp != stack_start)
11555                                         UNVERIFIED;
11556                                 
11557                                 MONO_INST_NEW (cfg, ins, OP_BR);
11558                                 ins->inst_target_bb = end_bblock;
11559                                 MONO_ADD_INS (bblock, ins);
11560                                 link_bblock (cfg, bblock, end_bblock);
11561                                 start_new_bblock = 1;
11562                                 ip += 6;
11563                                 break;
11564                         }
11565                         case CEE_MONO_CISINST:
11566                         case CEE_MONO_CCASTCLASS: {
11567                                 int token;
11568                                 CHECK_STACK (1);
11569                                 --sp;
11570                                 CHECK_OPSIZE (6);
11571                                 token = read32 (ip + 2);
11572                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11573                                 if (ip [1] == CEE_MONO_CISINST)
11574                                         ins = handle_cisinst (cfg, klass, sp [0]);
11575                                 else
11576                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11577                                 bblock = cfg->cbb;
11578                                 *sp++ = ins;
11579                                 ip += 6;
11580                                 break;
11581                         }
11582                         case CEE_MONO_SAVE_LMF:
11583                         case CEE_MONO_RESTORE_LMF:
11584 #ifdef MONO_ARCH_HAVE_LMF_OPS
11585                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11586                                 MONO_ADD_INS (bblock, ins);
11587                                 cfg->need_lmf_area = TRUE;
11588 #endif
11589                                 ip += 2;
11590                                 break;
11591                         case CEE_MONO_CLASSCONST:
11592                                 CHECK_STACK_OVF (1);
11593                                 CHECK_OPSIZE (6);
11594                                 token = read32 (ip + 2);
11595                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11596                                 *sp++ = ins;
11597                                 ip += 6;
11598                                 inline_costs += 10 * num_calls++;
11599                                 break;
11600                         case CEE_MONO_NOT_TAKEN:
11601                                 bblock->out_of_line = TRUE;
11602                                 ip += 2;
11603                                 break;
11604                         case CEE_MONO_TLS: {
11605                                 int key;
11606
11607                                 CHECK_STACK_OVF (1);
11608                                 CHECK_OPSIZE (6);
11609                                 key = (gint32)read32 (ip + 2);
11610                                 g_assert (key < TLS_KEY_NUM);
11611
11612                                 ins = mono_create_tls_get (cfg, key);
11613                                 if (!ins) {
11614                                         if (cfg->compile_aot) {
11615                                                 DISABLE_AOT (cfg);
11616                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11617                                                 ins->dreg = alloc_preg (cfg);
11618                                                 ins->type = STACK_PTR;
11619                                         } else {
11620                                                 g_assert_not_reached ();
11621                                         }
11622                                 }
11623                                 ins->type = STACK_PTR;
11624                                 MONO_ADD_INS (bblock, ins);
11625                                 *sp++ = ins;
11626                                 ip += 6;
11627                                 break;
11628                         }
11629                         case CEE_MONO_DYN_CALL: {
11630                                 MonoCallInst *call;
11631
11632                                 /* It would be easier to call a trampoline, but that would put an
11633                                  * extra frame on the stack, confusing exception handling. So
11634                                  * implement it inline using an opcode for now.
11635                                  */
11636
11637                                 if (!cfg->dyn_call_var) {
11638                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11639                                         /* prevent it from being register allocated */
11640                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11641                                 }
11642
11643                                 /* Has to use a call inst since it local regalloc expects it */
11644                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11645                                 ins = (MonoInst*)call;
11646                                 sp -= 2;
11647                                 ins->sreg1 = sp [0]->dreg;
11648                                 ins->sreg2 = sp [1]->dreg;
11649                                 MONO_ADD_INS (bblock, ins);
11650
11651                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11652
11653                                 ip += 2;
11654                                 inline_costs += 10 * num_calls++;
11655
11656                                 break;
11657                         }
11658                         case CEE_MONO_MEMORY_BARRIER: {
11659                                 CHECK_OPSIZE (5);
11660                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11661                                 ip += 5;
11662                                 break;
11663                         }
11664                         case CEE_MONO_JIT_ATTACH: {
11665                                 MonoInst *args [16], *domain_ins;
11666                                 MonoInst *ad_ins, *jit_tls_ins;
11667                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
11668
11669                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11670
11671                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11672                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11673
11674                                 ad_ins = mono_get_domain_intrinsic (cfg);
11675                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
11676
11677                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
11678                                         NEW_BBLOCK (cfg, next_bb);
11679                                         NEW_BBLOCK (cfg, call_bb);
11680
11681                                         if (cfg->compile_aot) {
11682                                                 /* AOT code is only used in the root domain */
11683                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
11684                                         } else {
11685                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
11686                                         }
11687                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11688                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
11689                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
11690
11691                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
11692                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
11693                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
11694
11695                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
11696                                         MONO_START_BB (cfg, call_bb);
11697                                 }
11698
11699                                 if (cfg->compile_aot) {
11700                                         /* AOT code is only used in the root domain */
11701                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11702                                 } else {
11703                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11704                                 }
11705                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11706                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11707
11708                                 if (next_bb) {
11709                                         MONO_START_BB (cfg, next_bb);
11710                                         bblock = cfg->cbb;
11711                                 }
11712                                 ip += 2;
11713                                 break;
11714                         }
11715                         case CEE_MONO_JIT_DETACH: {
11716                                 MonoInst *args [16];
11717
11718                                 /* Restore the original domain */
11719                                 dreg = alloc_ireg (cfg);
11720                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11721                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11722                                 ip += 2;
11723                                 break;
11724                         }
11725                         default:
11726                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11727                                 break;
11728                         }
11729                         break;
11730                 }
11731
11732                 case CEE_PREFIX1: {
11733                         CHECK_OPSIZE (2);
11734                         switch (ip [1]) {
11735                         case CEE_ARGLIST: {
11736                                 /* somewhat similar to LDTOKEN */
11737                                 MonoInst *addr, *vtvar;
11738                                 CHECK_STACK_OVF (1);
11739                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11740
11741                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11742                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11743
11744                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11745                                 ins->type = STACK_VTYPE;
11746                                 ins->klass = mono_defaults.argumenthandle_class;
11747                                 *sp++ = ins;
11748                                 ip += 2;
11749                                 break;
11750                         }
11751                         case CEE_CEQ:
11752                         case CEE_CGT:
11753                         case CEE_CGT_UN:
11754                         case CEE_CLT:
11755                         case CEE_CLT_UN: {
11756                                 MonoInst *cmp;
11757                                 CHECK_STACK (2);
11758                                 /*
11759                                  * The following transforms:
11760                                  *    CEE_CEQ    into OP_CEQ
11761                                  *    CEE_CGT    into OP_CGT
11762                                  *    CEE_CGT_UN into OP_CGT_UN
11763                                  *    CEE_CLT    into OP_CLT
11764                                  *    CEE_CLT_UN into OP_CLT_UN
11765                                  */
11766                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11767                                 
11768                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11769                                 sp -= 2;
11770                                 cmp->sreg1 = sp [0]->dreg;
11771                                 cmp->sreg2 = sp [1]->dreg;
11772                                 type_from_op (cmp, sp [0], sp [1]);
11773                                 CHECK_TYPE (cmp);
11774                                 if ((sp [0]->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
11775                                         cmp->opcode = OP_LCOMPARE;
11776                                 else if (sp [0]->type == STACK_R8)
11777                                         cmp->opcode = OP_FCOMPARE;
11778                                 else
11779                                         cmp->opcode = OP_ICOMPARE;
11780                                 MONO_ADD_INS (bblock, cmp);
11781                                 ins->type = STACK_I4;
11782                                 ins->dreg = alloc_dreg (cfg, ins->type);
11783                                 type_from_op (ins, sp [0], sp [1]);
11784
11785                                 if (cmp->opcode == OP_FCOMPARE) {
11786                                         /*
11787                                          * The backends expect the fceq opcodes to do the
11788                                          * comparison too.
11789                                          */
11790                                         cmp->opcode = OP_NOP;
11791                                         ins->sreg1 = cmp->sreg1;
11792                                         ins->sreg2 = cmp->sreg2;
11793                                 }
11794                                 MONO_ADD_INS (bblock, ins);
11795                                 *sp++ = ins;
11796                                 ip += 2;
11797                                 break;
11798                         }
11799                         case CEE_LDFTN: {
11800                                 MonoInst *argconst;
11801                                 MonoMethod *cil_method;
11802
11803                                 CHECK_STACK_OVF (1);
11804                                 CHECK_OPSIZE (6);
11805                                 n = read32 (ip + 2);
11806                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11807                                 if (!cmethod || mono_loader_get_last_error ())
11808                                         LOAD_ERROR;
11809                                 mono_class_init (cmethod->klass);
11810
11811                                 mono_save_token_info (cfg, image, n, cmethod);
11812
11813                                 context_used = mini_method_check_context_used (cfg, cmethod);
11814
11815                                 cil_method = cmethod;
11816                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11817                                         METHOD_ACCESS_FAILURE (method, cil_method);
11818
11819                                 if (mono_security_cas_enabled ()) {
11820                                         if (check_linkdemand (cfg, method, cmethod))
11821                                                 INLINE_FAILURE ("linkdemand");
11822                                         CHECK_CFG_EXCEPTION;
11823                                 } else if (mono_security_core_clr_enabled ()) {
11824                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11825                                 }
11826
11827                                 /* 
11828                                  * Optimize the common case of ldftn+delegate creation
11829                                  */
11830                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11831                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11832                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11833                                                 MonoInst *target_ins, *handle_ins;
11834                                                 MonoMethod *invoke;
11835                                                 int invoke_context_used;
11836
11837                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11838                                                 if (!invoke || !mono_method_signature (invoke))
11839                                                         LOAD_ERROR;
11840
11841                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11842
11843                                                 target_ins = sp [-1];
11844
11845                                                 if (mono_security_core_clr_enabled ())
11846                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11847
11848                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11849                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11850                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11851                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11852                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11853                                                         }
11854                                                 }
11855
11856 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11857                                                 /* FIXME: SGEN support */
11858                                                 if (invoke_context_used == 0) {
11859                                                         ip += 6;
11860                                                         if (cfg->verbose_level > 3)
11861                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11862                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
11863                                                                 sp --;
11864                                                                 *sp = handle_ins;
11865                                                                 CHECK_CFG_EXCEPTION;
11866                                                                 ip += 5;
11867                                                                 sp ++;
11868                                                                 break;
11869                                                         }
11870                                                         ip -= 6;
11871                                                 }
11872 #endif
11873                                         }
11874                                 }
11875
11876                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11877                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11878                                 *sp++ = ins;
11879                                 
11880                                 ip += 6;
11881                                 inline_costs += 10 * num_calls++;
11882                                 break;
11883                         }
11884                         case CEE_LDVIRTFTN: {
11885                                 MonoInst *args [2];
11886
11887                                 CHECK_STACK (1);
11888                                 CHECK_OPSIZE (6);
11889                                 n = read32 (ip + 2);
11890                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11891                                 if (!cmethod || mono_loader_get_last_error ())
11892                                         LOAD_ERROR;
11893                                 mono_class_init (cmethod->klass);
11894  
11895                                 context_used = mini_method_check_context_used (cfg, cmethod);
11896
11897                                 if (mono_security_cas_enabled ()) {
11898                                         if (check_linkdemand (cfg, method, cmethod))
11899                                                 INLINE_FAILURE ("linkdemand");
11900                                         CHECK_CFG_EXCEPTION;
11901                                 } else if (mono_security_core_clr_enabled ()) {
11902                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11903                                 }
11904
11905                                 /*
11906                                  * Optimize the common case of ldvirtftn+delegate creation
11907                                  */
11908                                 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)) {
11909                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11910                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11911                                                 MonoInst *target_ins, *handle_ins;
11912                                                 MonoMethod *invoke;
11913                                                 int invoke_context_used;
11914
11915                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11916                                                 if (!invoke || !mono_method_signature (invoke))
11917                                                         LOAD_ERROR;
11918
11919                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11920
11921                                                 target_ins = sp [-1];
11922
11923                                                 if (mono_security_core_clr_enabled ())
11924                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11925
11926 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11927                                                 /* FIXME: SGEN support */
11928                                                 if (invoke_context_used == 0) {
11929                                                         ip += 6;
11930                                                         if (cfg->verbose_level > 3)
11931                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11932                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, TRUE))) {
11933                                                                 sp -= 2;
11934                                                                 *sp = handle_ins;
11935                                                                 CHECK_CFG_EXCEPTION;
11936                                                                 ip += 5;
11937                                                                 sp ++;
11938                                                                 break;
11939                                                         }
11940                                                         ip -= 6;
11941                                                 }
11942 #endif
11943                                         }
11944                                 }
11945
11946                                 --sp;
11947                                 args [0] = *sp;
11948
11949                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11950                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11951
11952                                 if (context_used)
11953                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11954                                 else
11955                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11956
11957                                 ip += 6;
11958                                 inline_costs += 10 * num_calls++;
11959                                 break;
11960                         }
11961                         case CEE_LDARG:
11962                                 CHECK_STACK_OVF (1);
11963                                 CHECK_OPSIZE (4);
11964                                 n = read16 (ip + 2);
11965                                 CHECK_ARG (n);
11966                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11967                                 *sp++ = ins;
11968                                 ip += 4;
11969                                 break;
11970                         case CEE_LDARGA:
11971                                 CHECK_STACK_OVF (1);
11972                                 CHECK_OPSIZE (4);
11973                                 n = read16 (ip + 2);
11974                                 CHECK_ARG (n);
11975                                 NEW_ARGLOADA (cfg, ins, n);
11976                                 MONO_ADD_INS (cfg->cbb, ins);
11977                                 *sp++ = ins;
11978                                 ip += 4;
11979                                 break;
11980                         case CEE_STARG:
11981                                 CHECK_STACK (1);
11982                                 --sp;
11983                                 CHECK_OPSIZE (4);
11984                                 n = read16 (ip + 2);
11985                                 CHECK_ARG (n);
11986                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11987                                         UNVERIFIED;
11988                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11989                                 ip += 4;
11990                                 break;
11991                         case CEE_LDLOC:
11992                                 CHECK_STACK_OVF (1);
11993                                 CHECK_OPSIZE (4);
11994                                 n = read16 (ip + 2);
11995                                 CHECK_LOCAL (n);
11996                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11997                                 *sp++ = ins;
11998                                 ip += 4;
11999                                 break;
12000                         case CEE_LDLOCA: {
12001                                 unsigned char *tmp_ip;
12002                                 CHECK_STACK_OVF (1);
12003                                 CHECK_OPSIZE (4);
12004                                 n = read16 (ip + 2);
12005                                 CHECK_LOCAL (n);
12006
12007                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12008                                         ip = tmp_ip;
12009                                         inline_costs += 1;
12010                                         break;
12011                                 }                       
12012                                 
12013                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12014                                 *sp++ = ins;
12015                                 ip += 4;
12016                                 break;
12017                         }
12018                         case CEE_STLOC:
12019                                 CHECK_STACK (1);
12020                                 --sp;
12021                                 CHECK_OPSIZE (4);
12022                                 n = read16 (ip + 2);
12023                                 CHECK_LOCAL (n);
12024                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12025                                         UNVERIFIED;
12026                                 emit_stloc_ir (cfg, sp, header, n);
12027                                 ip += 4;
12028                                 inline_costs += 1;
12029                                 break;
12030                         case CEE_LOCALLOC:
12031                                 CHECK_STACK (1);
12032                                 --sp;
12033                                 if (sp != stack_start) 
12034                                         UNVERIFIED;
12035                                 if (cfg->method != method) 
12036                                         /* 
12037                                          * Inlining this into a loop in a parent could lead to 
12038                                          * stack overflows which is different behavior than the
12039                                          * non-inlined case, thus disable inlining in this case.
12040                                          */
12041                                         INLINE_FAILURE("localloc");
12042
12043                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12044                                 ins->dreg = alloc_preg (cfg);
12045                                 ins->sreg1 = sp [0]->dreg;
12046                                 ins->type = STACK_PTR;
12047                                 MONO_ADD_INS (cfg->cbb, ins);
12048
12049                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12050                                 if (init_locals)
12051                                         ins->flags |= MONO_INST_INIT;
12052
12053                                 *sp++ = ins;
12054                                 ip += 2;
12055                                 break;
12056                         case CEE_ENDFILTER: {
12057                                 MonoExceptionClause *clause, *nearest;
12058                                 int cc, nearest_num;
12059
12060                                 CHECK_STACK (1);
12061                                 --sp;
12062                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12063                                         UNVERIFIED;
12064                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12065                                 ins->sreg1 = (*sp)->dreg;
12066                                 MONO_ADD_INS (bblock, ins);
12067                                 start_new_bblock = 1;
12068                                 ip += 2;
12069
12070                                 nearest = NULL;
12071                                 nearest_num = 0;
12072                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12073                                         clause = &header->clauses [cc];
12074                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12075                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12076                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
12077                                                 nearest = clause;
12078                                                 nearest_num = cc;
12079                                         }
12080                                 }
12081                                 g_assert (nearest);
12082                                 if ((ip - header->code) != nearest->handler_offset)
12083                                         UNVERIFIED;
12084
12085                                 break;
12086                         }
12087                         case CEE_UNALIGNED_:
12088                                 ins_flag |= MONO_INST_UNALIGNED;
12089                                 /* FIXME: record alignment? we can assume 1 for now */
12090                                 CHECK_OPSIZE (3);
12091                                 ip += 3;
12092                                 break;
12093                         case CEE_VOLATILE_:
12094                                 ins_flag |= MONO_INST_VOLATILE;
12095                                 ip += 2;
12096                                 break;
12097                         case CEE_TAIL_:
12098                                 ins_flag   |= MONO_INST_TAILCALL;
12099                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12100                                 /* Can't inline tail calls at this time */
12101                                 inline_costs += 100000;
12102                                 ip += 2;
12103                                 break;
12104                         case CEE_INITOBJ:
12105                                 CHECK_STACK (1);
12106                                 --sp;
12107                                 CHECK_OPSIZE (6);
12108                                 token = read32 (ip + 2);
12109                                 klass = mini_get_class (method, token, generic_context);
12110                                 CHECK_TYPELOAD (klass);
12111                                 if (generic_class_is_reference_type (cfg, klass))
12112                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12113                                 else
12114                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12115                                 ip += 6;
12116                                 inline_costs += 1;
12117                                 break;
12118                         case CEE_CONSTRAINED_:
12119                                 CHECK_OPSIZE (6);
12120                                 token = read32 (ip + 2);
12121                                 constrained_call = mini_get_class (method, token, generic_context);
12122                                 CHECK_TYPELOAD (constrained_call);
12123                                 ip += 6;
12124                                 break;
12125                         case CEE_CPBLK:
12126                         case CEE_INITBLK: {
12127                                 MonoInst *iargs [3];
12128                                 CHECK_STACK (3);
12129                                 sp -= 3;
12130
12131                                 /* Skip optimized paths for volatile operations. */
12132                                 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)) {
12133                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12134                                 } 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)) {
12135                                         /* emit_memset only works when val == 0 */
12136                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12137                                 } else {
12138                                         MonoInst *call;
12139                                         iargs [0] = sp [0];
12140                                         iargs [1] = sp [1];
12141                                         iargs [2] = sp [2];
12142                                         if (ip [1] == CEE_CPBLK) {
12143                                                 /*
12144                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12145                                                  * and release barriers for cpblk. It is technically both a load and
12146                                                  * store operation, so it seems like that's the sensible thing to do.
12147                                                  */
12148                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12149                                                 if (ins_flag & MONO_INST_VOLATILE) {
12150                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12151                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
12152                                                         emit_memory_barrier (cfg, FullBarrier);
12153                                                 }
12154                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12155                                                 call->flags |= ins_flag;
12156                                                 if (ins_flag & MONO_INST_VOLATILE) {
12157                                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
12158                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
12159                                                         emit_memory_barrier (cfg, FullBarrier);
12160                                                 }
12161                                         } else {
12162                                                 MonoMethod *memset_method = get_memset_method ();
12163                                                 if (ins_flag & MONO_INST_VOLATILE) {
12164                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12165                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
12166                                                         emit_memory_barrier (cfg, FullBarrier);
12167                                                 }
12168                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12169                                                 call->flags |= ins_flag;
12170                                         }
12171                                 }
12172                                 ip += 2;
12173                                 ins_flag = 0;
12174                                 inline_costs += 1;
12175                                 break;
12176                         }
12177                         case CEE_NO_:
12178                                 CHECK_OPSIZE (3);
12179                                 if (ip [2] & 0x1)
12180                                         ins_flag |= MONO_INST_NOTYPECHECK;
12181                                 if (ip [2] & 0x2)
12182                                         ins_flag |= MONO_INST_NORANGECHECK;
12183                                 /* we ignore the no-nullcheck for now since we
12184                                  * really do it explicitly only when doing callvirt->call
12185                                  */
12186                                 ip += 3;
12187                                 break;
12188                         case CEE_RETHROW: {
12189                                 MonoInst *load;
12190                                 int handler_offset = -1;
12191
12192                                 for (i = 0; i < header->num_clauses; ++i) {
12193                                         MonoExceptionClause *clause = &header->clauses [i];
12194                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12195                                                 handler_offset = clause->handler_offset;
12196                                                 break;
12197                                         }
12198                                 }
12199
12200                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12201
12202                                 if (handler_offset == -1)
12203                                         UNVERIFIED;
12204
12205                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12206                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12207                                 ins->sreg1 = load->dreg;
12208                                 MONO_ADD_INS (bblock, ins);
12209
12210                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12211                                 MONO_ADD_INS (bblock, ins);
12212
12213                                 sp = stack_start;
12214                                 link_bblock (cfg, bblock, end_bblock);
12215                                 start_new_bblock = 1;
12216                                 ip += 2;
12217                                 break;
12218                         }
12219                         case CEE_SIZEOF: {
12220                                 guint32 val;
12221                                 int ialign;
12222
12223                                 CHECK_STACK_OVF (1);
12224                                 CHECK_OPSIZE (6);
12225                                 token = read32 (ip + 2);
12226                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12227                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &error);
12228                                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
12229                                         if (!type)
12230                                                 UNVERIFIED;
12231
12232                                         val = mono_type_size (type, &ialign);
12233                                 } else {
12234                                         MonoClass *klass = mono_class_get_and_inflate_typespec_checked (image, token, generic_context, &error);
12235                                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
12236                                         CHECK_TYPELOAD (klass);
12237                                         mono_class_init (klass);
12238                                         val = mono_type_size (&klass->byval_arg, &ialign);
12239
12240                                         if (mini_is_gsharedvt_klass (cfg, klass))
12241                                                 GSHAREDVT_FAILURE (*ip);
12242                                 }
12243                                 EMIT_NEW_ICONST (cfg, ins, val);
12244                                 *sp++= ins;
12245                                 ip += 6;
12246                                 break;
12247                         }
12248                         case CEE_REFANYTYPE: {
12249                                 MonoInst *src_var, *src;
12250
12251                                 GSHAREDVT_FAILURE (*ip);
12252
12253                                 CHECK_STACK (1);
12254                                 --sp;
12255
12256                                 // FIXME:
12257                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12258                                 if (!src_var)
12259                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12260                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12261                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12262                                 *sp++ = ins;
12263                                 ip += 2;
12264                                 break;
12265                         }
12266                         case CEE_READONLY_:
12267                                 readonly = TRUE;
12268                                 ip += 2;
12269                                 break;
12270
12271                         case CEE_UNUSED56:
12272                         case CEE_UNUSED57:
12273                         case CEE_UNUSED70:
12274                         case CEE_UNUSED:
12275                         case CEE_UNUSED99:
12276                                 UNVERIFIED;
12277                                 
12278                         default:
12279                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12280                                 UNVERIFIED;
12281                         }
12282                         break;
12283                 }
12284                 case CEE_UNUSED58:
12285                 case CEE_UNUSED1:
12286                         UNVERIFIED;
12287
12288                 default:
12289                         g_warning ("opcode 0x%02x not handled", *ip);
12290                         UNVERIFIED;
12291                 }
12292         }
12293         if (start_new_bblock != 1)
12294                 UNVERIFIED;
12295
12296         bblock->cil_length = ip - bblock->cil_code;
12297         if (bblock->next_bb) {
12298                 /* This could already be set because of inlining, #693905 */
12299                 MonoBasicBlock *bb = bblock;
12300
12301                 while (bb->next_bb)
12302                         bb = bb->next_bb;
12303                 bb->next_bb = end_bblock;
12304         } else {
12305                 bblock->next_bb = end_bblock;
12306         }
12307
12308         if (cfg->method == method && cfg->domainvar) {
12309                 MonoInst *store;
12310                 MonoInst *get_domain;
12311
12312                 cfg->cbb = init_localsbb;
12313
12314                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12315                         MONO_ADD_INS (cfg->cbb, get_domain);
12316                 } else {
12317                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12318                 }
12319                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12320                 MONO_ADD_INS (cfg->cbb, store);
12321         }
12322
12323 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12324         if (cfg->compile_aot)
12325                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12326                 mono_get_got_var (cfg);
12327 #endif
12328
12329         if (cfg->method == method && cfg->got_var)
12330                 mono_emit_load_got_addr (cfg);
12331
12332         if (init_localsbb) {
12333                 cfg->cbb = init_localsbb;
12334                 cfg->ip = NULL;
12335                 for (i = 0; i < header->num_locals; ++i) {
12336                         emit_init_local (cfg, i, header->locals [i], init_locals);
12337                 }
12338         }
12339
12340         if (cfg->init_ref_vars && cfg->method == method) {
12341                 /* Emit initialization for ref vars */
12342                 // FIXME: Avoid duplication initialization for IL locals.
12343                 for (i = 0; i < cfg->num_varinfo; ++i) {
12344                         MonoInst *ins = cfg->varinfo [i];
12345
12346                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12347                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12348                 }
12349         }
12350
12351         if (cfg->lmf_var && cfg->method == method) {
12352                 cfg->cbb = init_localsbb;
12353                 emit_push_lmf (cfg);
12354         }
12355
12356         cfg->cbb = init_localsbb;
12357         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12358
12359         if (seq_points) {
12360                 MonoBasicBlock *bb;
12361
12362                 /*
12363                  * Make seq points at backward branch targets interruptable.
12364                  */
12365                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12366                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12367                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12368         }
12369
12370         /* Add a sequence point for method entry/exit events */
12371         if (seq_points) {
12372                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12373                 MONO_ADD_INS (init_localsbb, ins);
12374                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12375                 MONO_ADD_INS (cfg->bb_exit, ins);
12376         }
12377
12378         /*
12379          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12380          * the code they refer to was dead (#11880).
12381          */
12382         if (sym_seq_points) {
12383                 for (i = 0; i < header->code_size; ++i) {
12384                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12385                                 MonoInst *ins;
12386
12387                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12388                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12389                         }
12390                 }
12391         }
12392
12393         cfg->ip = NULL;
12394
12395         if (cfg->method == method) {
12396                 MonoBasicBlock *bb;
12397                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12398                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12399                         if (cfg->spvars)
12400                                 mono_create_spvar_for_region (cfg, bb->region);
12401                         if (cfg->verbose_level > 2)
12402                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12403                 }
12404         }
12405
12406         if (inline_costs < 0) {
12407                 char *mname;
12408
12409                 /* Method is too large */
12410                 mname = mono_method_full_name (method, TRUE);
12411                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12412                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12413                 g_free (mname);
12414         }
12415
12416         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12417                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12418
12419         goto cleanup;
12420  
12421  exception_exit:
12422         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12423         goto cleanup;
12424
12425  unverified:
12426         set_exception_type_from_invalid_il (cfg, method, ip);
12427         goto cleanup;
12428
12429  cleanup:
12430         g_slist_free (class_inits);
12431         mono_basic_block_free (original_bb);
12432         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
12433         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12434         if (cfg->exception_type)
12435                 return -1;
12436         else
12437                 return inline_costs;
12438 }
12439
12440 static int
12441 store_membase_reg_to_store_membase_imm (int opcode)
12442 {
12443         switch (opcode) {
12444         case OP_STORE_MEMBASE_REG:
12445                 return OP_STORE_MEMBASE_IMM;
12446         case OP_STOREI1_MEMBASE_REG:
12447                 return OP_STOREI1_MEMBASE_IMM;
12448         case OP_STOREI2_MEMBASE_REG:
12449                 return OP_STOREI2_MEMBASE_IMM;
12450         case OP_STOREI4_MEMBASE_REG:
12451                 return OP_STOREI4_MEMBASE_IMM;
12452         case OP_STOREI8_MEMBASE_REG:
12453                 return OP_STOREI8_MEMBASE_IMM;
12454         default:
12455                 g_assert_not_reached ();
12456         }
12457
12458         return -1;
12459 }               
12460
12461 int
12462 mono_op_to_op_imm (int opcode)
12463 {
12464         switch (opcode) {
12465         case OP_IADD:
12466                 return OP_IADD_IMM;
12467         case OP_ISUB:
12468                 return OP_ISUB_IMM;
12469         case OP_IDIV:
12470                 return OP_IDIV_IMM;
12471         case OP_IDIV_UN:
12472                 return OP_IDIV_UN_IMM;
12473         case OP_IREM:
12474                 return OP_IREM_IMM;
12475         case OP_IREM_UN:
12476                 return OP_IREM_UN_IMM;
12477         case OP_IMUL:
12478                 return OP_IMUL_IMM;
12479         case OP_IAND:
12480                 return OP_IAND_IMM;
12481         case OP_IOR:
12482                 return OP_IOR_IMM;
12483         case OP_IXOR:
12484                 return OP_IXOR_IMM;
12485         case OP_ISHL:
12486                 return OP_ISHL_IMM;
12487         case OP_ISHR:
12488                 return OP_ISHR_IMM;
12489         case OP_ISHR_UN:
12490                 return OP_ISHR_UN_IMM;
12491
12492         case OP_LADD:
12493                 return OP_LADD_IMM;
12494         case OP_LSUB:
12495                 return OP_LSUB_IMM;
12496         case OP_LAND:
12497                 return OP_LAND_IMM;
12498         case OP_LOR:
12499                 return OP_LOR_IMM;
12500         case OP_LXOR:
12501                 return OP_LXOR_IMM;
12502         case OP_LSHL:
12503                 return OP_LSHL_IMM;
12504         case OP_LSHR:
12505                 return OP_LSHR_IMM;
12506         case OP_LSHR_UN:
12507                 return OP_LSHR_UN_IMM;
12508 #if SIZEOF_REGISTER == 8
12509         case OP_LREM:
12510                 return OP_LREM_IMM;
12511 #endif
12512
12513         case OP_COMPARE:
12514                 return OP_COMPARE_IMM;
12515         case OP_ICOMPARE:
12516                 return OP_ICOMPARE_IMM;
12517         case OP_LCOMPARE:
12518                 return OP_LCOMPARE_IMM;
12519
12520         case OP_STORE_MEMBASE_REG:
12521                 return OP_STORE_MEMBASE_IMM;
12522         case OP_STOREI1_MEMBASE_REG:
12523                 return OP_STOREI1_MEMBASE_IMM;
12524         case OP_STOREI2_MEMBASE_REG:
12525                 return OP_STOREI2_MEMBASE_IMM;
12526         case OP_STOREI4_MEMBASE_REG:
12527                 return OP_STOREI4_MEMBASE_IMM;
12528
12529 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12530         case OP_X86_PUSH:
12531                 return OP_X86_PUSH_IMM;
12532         case OP_X86_COMPARE_MEMBASE_REG:
12533                 return OP_X86_COMPARE_MEMBASE_IMM;
12534 #endif
12535 #if defined(TARGET_AMD64)
12536         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12537                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12538 #endif
12539         case OP_VOIDCALL_REG:
12540                 return OP_VOIDCALL;
12541         case OP_CALL_REG:
12542                 return OP_CALL;
12543         case OP_LCALL_REG:
12544                 return OP_LCALL;
12545         case OP_FCALL_REG:
12546                 return OP_FCALL;
12547         case OP_LOCALLOC:
12548                 return OP_LOCALLOC_IMM;
12549         }
12550
12551         return -1;
12552 }
12553
12554 static int
12555 ldind_to_load_membase (int opcode)
12556 {
12557         switch (opcode) {
12558         case CEE_LDIND_I1:
12559                 return OP_LOADI1_MEMBASE;
12560         case CEE_LDIND_U1:
12561                 return OP_LOADU1_MEMBASE;
12562         case CEE_LDIND_I2:
12563                 return OP_LOADI2_MEMBASE;
12564         case CEE_LDIND_U2:
12565                 return OP_LOADU2_MEMBASE;
12566         case CEE_LDIND_I4:
12567                 return OP_LOADI4_MEMBASE;
12568         case CEE_LDIND_U4:
12569                 return OP_LOADU4_MEMBASE;
12570         case CEE_LDIND_I:
12571                 return OP_LOAD_MEMBASE;
12572         case CEE_LDIND_REF:
12573                 return OP_LOAD_MEMBASE;
12574         case CEE_LDIND_I8:
12575                 return OP_LOADI8_MEMBASE;
12576         case CEE_LDIND_R4:
12577                 return OP_LOADR4_MEMBASE;
12578         case CEE_LDIND_R8:
12579                 return OP_LOADR8_MEMBASE;
12580         default:
12581                 g_assert_not_reached ();
12582         }
12583
12584         return -1;
12585 }
12586
12587 static int
12588 stind_to_store_membase (int opcode)
12589 {
12590         switch (opcode) {
12591         case CEE_STIND_I1:
12592                 return OP_STOREI1_MEMBASE_REG;
12593         case CEE_STIND_I2:
12594                 return OP_STOREI2_MEMBASE_REG;
12595         case CEE_STIND_I4:
12596                 return OP_STOREI4_MEMBASE_REG;
12597         case CEE_STIND_I:
12598         case CEE_STIND_REF:
12599                 return OP_STORE_MEMBASE_REG;
12600         case CEE_STIND_I8:
12601                 return OP_STOREI8_MEMBASE_REG;
12602         case CEE_STIND_R4:
12603                 return OP_STORER4_MEMBASE_REG;
12604         case CEE_STIND_R8:
12605                 return OP_STORER8_MEMBASE_REG;
12606         default:
12607                 g_assert_not_reached ();
12608         }
12609
12610         return -1;
12611 }
12612
12613 int
12614 mono_load_membase_to_load_mem (int opcode)
12615 {
12616         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12617 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12618         switch (opcode) {
12619         case OP_LOAD_MEMBASE:
12620                 return OP_LOAD_MEM;
12621         case OP_LOADU1_MEMBASE:
12622                 return OP_LOADU1_MEM;
12623         case OP_LOADU2_MEMBASE:
12624                 return OP_LOADU2_MEM;
12625         case OP_LOADI4_MEMBASE:
12626                 return OP_LOADI4_MEM;
12627         case OP_LOADU4_MEMBASE:
12628                 return OP_LOADU4_MEM;
12629 #if SIZEOF_REGISTER == 8
12630         case OP_LOADI8_MEMBASE:
12631                 return OP_LOADI8_MEM;
12632 #endif
12633         }
12634 #endif
12635
12636         return -1;
12637 }
12638
12639 static inline int
12640 op_to_op_dest_membase (int store_opcode, int opcode)
12641 {
12642 #if defined(TARGET_X86)
12643         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12644                 return -1;
12645
12646         switch (opcode) {
12647         case OP_IADD:
12648                 return OP_X86_ADD_MEMBASE_REG;
12649         case OP_ISUB:
12650                 return OP_X86_SUB_MEMBASE_REG;
12651         case OP_IAND:
12652                 return OP_X86_AND_MEMBASE_REG;
12653         case OP_IOR:
12654                 return OP_X86_OR_MEMBASE_REG;
12655         case OP_IXOR:
12656                 return OP_X86_XOR_MEMBASE_REG;
12657         case OP_ADD_IMM:
12658         case OP_IADD_IMM:
12659                 return OP_X86_ADD_MEMBASE_IMM;
12660         case OP_SUB_IMM:
12661         case OP_ISUB_IMM:
12662                 return OP_X86_SUB_MEMBASE_IMM;
12663         case OP_AND_IMM:
12664         case OP_IAND_IMM:
12665                 return OP_X86_AND_MEMBASE_IMM;
12666         case OP_OR_IMM:
12667         case OP_IOR_IMM:
12668                 return OP_X86_OR_MEMBASE_IMM;
12669         case OP_XOR_IMM:
12670         case OP_IXOR_IMM:
12671                 return OP_X86_XOR_MEMBASE_IMM;
12672         case OP_MOVE:
12673                 return OP_NOP;
12674         }
12675 #endif
12676
12677 #if defined(TARGET_AMD64)
12678         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12679                 return -1;
12680
12681         switch (opcode) {
12682         case OP_IADD:
12683                 return OP_X86_ADD_MEMBASE_REG;
12684         case OP_ISUB:
12685                 return OP_X86_SUB_MEMBASE_REG;
12686         case OP_IAND:
12687                 return OP_X86_AND_MEMBASE_REG;
12688         case OP_IOR:
12689                 return OP_X86_OR_MEMBASE_REG;
12690         case OP_IXOR:
12691                 return OP_X86_XOR_MEMBASE_REG;
12692         case OP_IADD_IMM:
12693                 return OP_X86_ADD_MEMBASE_IMM;
12694         case OP_ISUB_IMM:
12695                 return OP_X86_SUB_MEMBASE_IMM;
12696         case OP_IAND_IMM:
12697                 return OP_X86_AND_MEMBASE_IMM;
12698         case OP_IOR_IMM:
12699                 return OP_X86_OR_MEMBASE_IMM;
12700         case OP_IXOR_IMM:
12701                 return OP_X86_XOR_MEMBASE_IMM;
12702         case OP_LADD:
12703                 return OP_AMD64_ADD_MEMBASE_REG;
12704         case OP_LSUB:
12705                 return OP_AMD64_SUB_MEMBASE_REG;
12706         case OP_LAND:
12707                 return OP_AMD64_AND_MEMBASE_REG;
12708         case OP_LOR:
12709                 return OP_AMD64_OR_MEMBASE_REG;
12710         case OP_LXOR:
12711                 return OP_AMD64_XOR_MEMBASE_REG;
12712         case OP_ADD_IMM:
12713         case OP_LADD_IMM:
12714                 return OP_AMD64_ADD_MEMBASE_IMM;
12715         case OP_SUB_IMM:
12716         case OP_LSUB_IMM:
12717                 return OP_AMD64_SUB_MEMBASE_IMM;
12718         case OP_AND_IMM:
12719         case OP_LAND_IMM:
12720                 return OP_AMD64_AND_MEMBASE_IMM;
12721         case OP_OR_IMM:
12722         case OP_LOR_IMM:
12723                 return OP_AMD64_OR_MEMBASE_IMM;
12724         case OP_XOR_IMM:
12725         case OP_LXOR_IMM:
12726                 return OP_AMD64_XOR_MEMBASE_IMM;
12727         case OP_MOVE:
12728                 return OP_NOP;
12729         }
12730 #endif
12731
12732         return -1;
12733 }
12734
12735 static inline int
12736 op_to_op_store_membase (int store_opcode, int opcode)
12737 {
12738 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12739         switch (opcode) {
12740         case OP_ICEQ:
12741                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12742                         return OP_X86_SETEQ_MEMBASE;
12743         case OP_CNE:
12744                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12745                         return OP_X86_SETNE_MEMBASE;
12746         }
12747 #endif
12748
12749         return -1;
12750 }
12751
12752 static inline int
12753 op_to_op_src1_membase (int load_opcode, int opcode)
12754 {
12755 #ifdef TARGET_X86
12756         /* FIXME: This has sign extension issues */
12757         /*
12758         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12759                 return OP_X86_COMPARE_MEMBASE8_IMM;
12760         */
12761
12762         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12763                 return -1;
12764
12765         switch (opcode) {
12766         case OP_X86_PUSH:
12767                 return OP_X86_PUSH_MEMBASE;
12768         case OP_COMPARE_IMM:
12769         case OP_ICOMPARE_IMM:
12770                 return OP_X86_COMPARE_MEMBASE_IMM;
12771         case OP_COMPARE:
12772         case OP_ICOMPARE:
12773                 return OP_X86_COMPARE_MEMBASE_REG;
12774         }
12775 #endif
12776
12777 #ifdef TARGET_AMD64
12778         /* FIXME: This has sign extension issues */
12779         /*
12780         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12781                 return OP_X86_COMPARE_MEMBASE8_IMM;
12782         */
12783
12784         switch (opcode) {
12785         case OP_X86_PUSH:
12786 #ifdef __mono_ilp32__
12787                 if (load_opcode == OP_LOADI8_MEMBASE)
12788 #else
12789                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12790 #endif
12791                         return OP_X86_PUSH_MEMBASE;
12792                 break;
12793                 /* FIXME: This only works for 32 bit immediates
12794         case OP_COMPARE_IMM:
12795         case OP_LCOMPARE_IMM:
12796                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12797                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12798                 */
12799         case OP_ICOMPARE_IMM:
12800                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12801                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12802                 break;
12803         case OP_COMPARE:
12804         case OP_LCOMPARE:
12805 #ifdef __mono_ilp32__
12806                 if (load_opcode == OP_LOAD_MEMBASE)
12807                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12808                 if (load_opcode == OP_LOADI8_MEMBASE)
12809 #else
12810                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12811 #endif
12812                         return OP_AMD64_COMPARE_MEMBASE_REG;
12813                 break;
12814         case OP_ICOMPARE:
12815                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12816                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12817                 break;
12818         }
12819 #endif
12820
12821         return -1;
12822 }
12823
12824 static inline int
12825 op_to_op_src2_membase (int load_opcode, int opcode)
12826 {
12827 #ifdef TARGET_X86
12828         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12829                 return -1;
12830         
12831         switch (opcode) {
12832         case OP_COMPARE:
12833         case OP_ICOMPARE:
12834                 return OP_X86_COMPARE_REG_MEMBASE;
12835         case OP_IADD:
12836                 return OP_X86_ADD_REG_MEMBASE;
12837         case OP_ISUB:
12838                 return OP_X86_SUB_REG_MEMBASE;
12839         case OP_IAND:
12840                 return OP_X86_AND_REG_MEMBASE;
12841         case OP_IOR:
12842                 return OP_X86_OR_REG_MEMBASE;
12843         case OP_IXOR:
12844                 return OP_X86_XOR_REG_MEMBASE;
12845         }
12846 #endif
12847
12848 #ifdef TARGET_AMD64
12849 #ifdef __mono_ilp32__
12850         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12851 #else
12852         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12853 #endif
12854                 switch (opcode) {
12855                 case OP_ICOMPARE:
12856                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12857                 case OP_IADD:
12858                         return OP_X86_ADD_REG_MEMBASE;
12859                 case OP_ISUB:
12860                         return OP_X86_SUB_REG_MEMBASE;
12861                 case OP_IAND:
12862                         return OP_X86_AND_REG_MEMBASE;
12863                 case OP_IOR:
12864                         return OP_X86_OR_REG_MEMBASE;
12865                 case OP_IXOR:
12866                         return OP_X86_XOR_REG_MEMBASE;
12867                 }
12868 #ifdef __mono_ilp32__
12869         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12870 #else
12871         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12872 #endif
12873                 switch (opcode) {
12874                 case OP_COMPARE:
12875                 case OP_LCOMPARE:
12876                         return OP_AMD64_COMPARE_REG_MEMBASE;
12877                 case OP_LADD:
12878                         return OP_AMD64_ADD_REG_MEMBASE;
12879                 case OP_LSUB:
12880                         return OP_AMD64_SUB_REG_MEMBASE;
12881                 case OP_LAND:
12882                         return OP_AMD64_AND_REG_MEMBASE;
12883                 case OP_LOR:
12884                         return OP_AMD64_OR_REG_MEMBASE;
12885                 case OP_LXOR:
12886                         return OP_AMD64_XOR_REG_MEMBASE;
12887                 }
12888         }
12889 #endif
12890
12891         return -1;
12892 }
12893
12894 int
12895 mono_op_to_op_imm_noemul (int opcode)
12896 {
12897         switch (opcode) {
12898 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12899         case OP_LSHR:
12900         case OP_LSHL:
12901         case OP_LSHR_UN:
12902                 return -1;
12903 #endif
12904 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12905         case OP_IDIV:
12906         case OP_IDIV_UN:
12907         case OP_IREM:
12908         case OP_IREM_UN:
12909                 return -1;
12910 #endif
12911 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12912         case OP_IMUL:
12913                 return -1;
12914 #endif
12915         default:
12916                 return mono_op_to_op_imm (opcode);
12917         }
12918 }
12919
12920 /**
12921  * mono_handle_global_vregs:
12922  *
12923  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12924  * for them.
12925  */
12926 void
12927 mono_handle_global_vregs (MonoCompile *cfg)
12928 {
12929         gint32 *vreg_to_bb;
12930         MonoBasicBlock *bb;
12931         int i, pos;
12932
12933         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12934
12935 #ifdef MONO_ARCH_SIMD_INTRINSICS
12936         if (cfg->uses_simd_intrinsics)
12937                 mono_simd_simplify_indirection (cfg);
12938 #endif
12939
12940         /* Find local vregs used in more than one bb */
12941         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12942                 MonoInst *ins = bb->code;       
12943                 int block_num = bb->block_num;
12944
12945                 if (cfg->verbose_level > 2)
12946                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12947
12948                 cfg->cbb = bb;
12949                 for (; ins; ins = ins->next) {
12950                         const char *spec = INS_INFO (ins->opcode);
12951                         int regtype = 0, regindex;
12952                         gint32 prev_bb;
12953
12954                         if (G_UNLIKELY (cfg->verbose_level > 2))
12955                                 mono_print_ins (ins);
12956
12957                         g_assert (ins->opcode >= MONO_CEE_LAST);
12958
12959                         for (regindex = 0; regindex < 4; regindex ++) {
12960                                 int vreg = 0;
12961
12962                                 if (regindex == 0) {
12963                                         regtype = spec [MONO_INST_DEST];
12964                                         if (regtype == ' ')
12965                                                 continue;
12966                                         vreg = ins->dreg;
12967                                 } else if (regindex == 1) {
12968                                         regtype = spec [MONO_INST_SRC1];
12969                                         if (regtype == ' ')
12970                                                 continue;
12971                                         vreg = ins->sreg1;
12972                                 } else if (regindex == 2) {
12973                                         regtype = spec [MONO_INST_SRC2];
12974                                         if (regtype == ' ')
12975                                                 continue;
12976                                         vreg = ins->sreg2;
12977                                 } else if (regindex == 3) {
12978                                         regtype = spec [MONO_INST_SRC3];
12979                                         if (regtype == ' ')
12980                                                 continue;
12981                                         vreg = ins->sreg3;
12982                                 }
12983
12984 #if SIZEOF_REGISTER == 4
12985                                 /* In the LLVM case, the long opcodes are not decomposed */
12986                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12987                                         /*
12988                                          * Since some instructions reference the original long vreg,
12989                                          * and some reference the two component vregs, it is quite hard
12990                                          * to determine when it needs to be global. So be conservative.
12991                                          */
12992                                         if (!get_vreg_to_inst (cfg, vreg)) {
12993                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12994
12995                                                 if (cfg->verbose_level > 2)
12996                                                         printf ("LONG VREG R%d made global.\n", vreg);
12997                                         }
12998
12999                                         /*
13000                                          * Make the component vregs volatile since the optimizations can
13001                                          * get confused otherwise.
13002                                          */
13003                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13004                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13005                                 }
13006 #endif
13007
13008                                 g_assert (vreg != -1);
13009
13010                                 prev_bb = vreg_to_bb [vreg];
13011                                 if (prev_bb == 0) {
13012                                         /* 0 is a valid block num */
13013                                         vreg_to_bb [vreg] = block_num + 1;
13014                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13015                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13016                                                 continue;
13017
13018                                         if (!get_vreg_to_inst (cfg, vreg)) {
13019                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13020                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13021
13022                                                 switch (regtype) {
13023                                                 case 'i':
13024                                                         if (vreg_is_ref (cfg, vreg))
13025                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13026                                                         else
13027                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13028                                                         break;
13029                                                 case 'l':
13030                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13031                                                         break;
13032                                                 case 'f':
13033                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13034                                                         break;
13035                                                 case 'v':
13036                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13037                                                         break;
13038                                                 default:
13039                                                         g_assert_not_reached ();
13040                                                 }
13041                                         }
13042
13043                                         /* Flag as having been used in more than one bb */
13044                                         vreg_to_bb [vreg] = -1;
13045                                 }
13046                         }
13047                 }
13048         }
13049
13050         /* If a variable is used in only one bblock, convert it into a local vreg */
13051         for (i = 0; i < cfg->num_varinfo; i++) {
13052                 MonoInst *var = cfg->varinfo [i];
13053                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13054
13055                 switch (var->type) {
13056                 case STACK_I4:
13057                 case STACK_OBJ:
13058                 case STACK_PTR:
13059                 case STACK_MP:
13060                 case STACK_VTYPE:
13061 #if SIZEOF_REGISTER == 8
13062                 case STACK_I8:
13063 #endif
13064 #if !defined(TARGET_X86)
13065                 /* Enabling this screws up the fp stack on x86 */
13066                 case STACK_R8:
13067 #endif
13068                         if (mono_arch_is_soft_float ())
13069                                 break;
13070
13071                         /* Arguments are implicitly global */
13072                         /* Putting R4 vars into registers doesn't work currently */
13073                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13074                         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) {
13075                                 /* 
13076                                  * Make that the variable's liveness interval doesn't contain a call, since
13077                                  * that would cause the lvreg to be spilled, making the whole optimization
13078                                  * useless.
13079                                  */
13080                                 /* This is too slow for JIT compilation */
13081 #if 0
13082                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13083                                         MonoInst *ins;
13084                                         int def_index, call_index, ins_index;
13085                                         gboolean spilled = FALSE;
13086
13087                                         def_index = -1;
13088                                         call_index = -1;
13089                                         ins_index = 0;
13090                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13091                                                 const char *spec = INS_INFO (ins->opcode);
13092
13093                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13094                                                         def_index = ins_index;
13095
13096                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13097                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13098                                                         if (call_index > def_index) {
13099                                                                 spilled = TRUE;
13100                                                                 break;
13101                                                         }
13102                                                 }
13103
13104                                                 if (MONO_IS_CALL (ins))
13105                                                         call_index = ins_index;
13106
13107                                                 ins_index ++;
13108                                         }
13109
13110                                         if (spilled)
13111                                                 break;
13112                                 }
13113 #endif
13114
13115                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13116                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13117                                 var->flags |= MONO_INST_IS_DEAD;
13118                                 cfg->vreg_to_inst [var->dreg] = NULL;
13119                         }
13120                         break;
13121                 }
13122         }
13123
13124         /* 
13125          * Compress the varinfo and vars tables so the liveness computation is faster and
13126          * takes up less space.
13127          */
13128         pos = 0;
13129         for (i = 0; i < cfg->num_varinfo; ++i) {
13130                 MonoInst *var = cfg->varinfo [i];
13131                 if (pos < i && cfg->locals_start == i)
13132                         cfg->locals_start = pos;
13133                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13134                         if (pos < i) {
13135                                 cfg->varinfo [pos] = cfg->varinfo [i];
13136                                 cfg->varinfo [pos]->inst_c0 = pos;
13137                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13138                                 cfg->vars [pos].idx = pos;
13139 #if SIZEOF_REGISTER == 4
13140                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13141                                         /* Modify the two component vars too */
13142                                         MonoInst *var1;
13143
13144                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13145                                         var1->inst_c0 = pos;
13146                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13147                                         var1->inst_c0 = pos;
13148                                 }
13149 #endif
13150                         }
13151                         pos ++;
13152                 }
13153         }
13154         cfg->num_varinfo = pos;
13155         if (cfg->locals_start > cfg->num_varinfo)
13156                 cfg->locals_start = cfg->num_varinfo;
13157 }
13158
13159 /**
13160  * mono_spill_global_vars:
13161  *
13162  *   Generate spill code for variables which are not allocated to registers, 
13163  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13164  * code is generated which could be optimized by the local optimization passes.
13165  */
13166 void
13167 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13168 {
13169         MonoBasicBlock *bb;
13170         char spec2 [16];
13171         int orig_next_vreg;
13172         guint32 *vreg_to_lvreg;
13173         guint32 *lvregs;
13174         guint32 i, lvregs_len;
13175         gboolean dest_has_lvreg = FALSE;
13176         guint32 stacktypes [128];
13177         MonoInst **live_range_start, **live_range_end;
13178         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13179         int *gsharedvt_vreg_to_idx = NULL;
13180
13181         *need_local_opts = FALSE;
13182
13183         memset (spec2, 0, sizeof (spec2));
13184
13185         /* FIXME: Move this function to mini.c */
13186         stacktypes ['i'] = STACK_PTR;
13187         stacktypes ['l'] = STACK_I8;
13188         stacktypes ['f'] = STACK_R8;
13189 #ifdef MONO_ARCH_SIMD_INTRINSICS
13190         stacktypes ['x'] = STACK_VTYPE;
13191 #endif
13192
13193 #if SIZEOF_REGISTER == 4
13194         /* Create MonoInsts for longs */
13195         for (i = 0; i < cfg->num_varinfo; i++) {
13196                 MonoInst *ins = cfg->varinfo [i];
13197
13198                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13199                         switch (ins->type) {
13200                         case STACK_R8:
13201                         case STACK_I8: {
13202                                 MonoInst *tree;
13203
13204                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13205                                         break;
13206
13207                                 g_assert (ins->opcode == OP_REGOFFSET);
13208
13209                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13210                                 g_assert (tree);
13211                                 tree->opcode = OP_REGOFFSET;
13212                                 tree->inst_basereg = ins->inst_basereg;
13213                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13214
13215                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13216                                 g_assert (tree);
13217                                 tree->opcode = OP_REGOFFSET;
13218                                 tree->inst_basereg = ins->inst_basereg;
13219                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13220                                 break;
13221                         }
13222                         default:
13223                                 break;
13224                         }
13225                 }
13226         }
13227 #endif
13228
13229         if (cfg->compute_gc_maps) {
13230                 /* registers need liveness info even for !non refs */
13231                 for (i = 0; i < cfg->num_varinfo; i++) {
13232                         MonoInst *ins = cfg->varinfo [i];
13233
13234                         if (ins->opcode == OP_REGVAR)
13235                                 ins->flags |= MONO_INST_GC_TRACK;
13236                 }
13237         }
13238
13239         if (cfg->gsharedvt) {
13240                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13241
13242                 for (i = 0; i < cfg->num_varinfo; ++i) {
13243                         MonoInst *ins = cfg->varinfo [i];
13244                         int idx;
13245
13246                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13247                                 if (i >= cfg->locals_start) {
13248                                         /* Local */
13249                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13250                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13251                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13252                                         ins->inst_imm = idx;
13253                                 } else {
13254                                         /* Arg */
13255                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13256                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13257                                 }
13258                         }
13259                 }
13260         }
13261                 
13262         /* FIXME: widening and truncation */
13263
13264         /*
13265          * As an optimization, when a variable allocated to the stack is first loaded into 
13266          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13267          * the variable again.
13268          */
13269         orig_next_vreg = cfg->next_vreg;
13270         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13271         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13272         lvregs_len = 0;
13273
13274         /* 
13275          * These arrays contain the first and last instructions accessing a given
13276          * variable.
13277          * Since we emit bblocks in the same order we process them here, and we
13278          * don't split live ranges, these will precisely describe the live range of
13279          * the variable, i.e. the instruction range where a valid value can be found
13280          * in the variables location.
13281          * The live range is computed using the liveness info computed by the liveness pass.
13282          * We can't use vmv->range, since that is an abstract live range, and we need
13283          * one which is instruction precise.
13284          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13285          */
13286         /* FIXME: Only do this if debugging info is requested */
13287         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13288         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13289         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13290         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13291         
13292         /* Add spill loads/stores */
13293         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13294                 MonoInst *ins;
13295
13296                 if (cfg->verbose_level > 2)
13297                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13298
13299                 /* Clear vreg_to_lvreg array */
13300                 for (i = 0; i < lvregs_len; i++)
13301                         vreg_to_lvreg [lvregs [i]] = 0;
13302                 lvregs_len = 0;
13303
13304                 cfg->cbb = bb;
13305                 MONO_BB_FOR_EACH_INS (bb, ins) {
13306                         const char *spec = INS_INFO (ins->opcode);
13307                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13308                         gboolean store, no_lvreg;
13309                         int sregs [MONO_MAX_SRC_REGS];
13310
13311                         if (G_UNLIKELY (cfg->verbose_level > 2))
13312                                 mono_print_ins (ins);
13313
13314                         if (ins->opcode == OP_NOP)
13315                                 continue;
13316
13317                         /* 
13318                          * We handle LDADDR here as well, since it can only be decomposed
13319                          * when variable addresses are known.
13320                          */
13321                         if (ins->opcode == OP_LDADDR) {
13322                                 MonoInst *var = ins->inst_p0;
13323
13324                                 if (var->opcode == OP_VTARG_ADDR) {
13325                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13326                                         MonoInst *vtaddr = var->inst_left;
13327                                         if (vtaddr->opcode == OP_REGVAR) {
13328                                                 ins->opcode = OP_MOVE;
13329                                                 ins->sreg1 = vtaddr->dreg;
13330                                         }
13331                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13332                                                 ins->opcode = OP_LOAD_MEMBASE;
13333                                                 ins->inst_basereg = vtaddr->inst_basereg;
13334                                                 ins->inst_offset = vtaddr->inst_offset;
13335                                         } else
13336                                                 NOT_IMPLEMENTED;
13337                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13338                                         /* gsharedvt arg passed by ref */
13339                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13340
13341                                         ins->opcode = OP_LOAD_MEMBASE;
13342                                         ins->inst_basereg = var->inst_basereg;
13343                                         ins->inst_offset = var->inst_offset;
13344                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13345                                         MonoInst *load, *load2, *load3;
13346                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13347                                         int reg1, reg2, reg3;
13348                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13349                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13350
13351                                         /*
13352                                          * gsharedvt local.
13353                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13354                                          */
13355
13356                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13357
13358                                         g_assert (info_var);
13359                                         g_assert (locals_var);
13360
13361                                         /* Mark the instruction used to compute the locals var as used */
13362                                         cfg->gsharedvt_locals_var_ins = NULL;
13363
13364                                         /* Load the offset */
13365                                         if (info_var->opcode == OP_REGOFFSET) {
13366                                                 reg1 = alloc_ireg (cfg);
13367                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13368                                         } else if (info_var->opcode == OP_REGVAR) {
13369                                                 load = NULL;
13370                                                 reg1 = info_var->dreg;
13371                                         } else {
13372                                                 g_assert_not_reached ();
13373                                         }
13374                                         reg2 = alloc_ireg (cfg);
13375                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13376                                         /* Load the locals area address */
13377                                         reg3 = alloc_ireg (cfg);
13378                                         if (locals_var->opcode == OP_REGOFFSET) {
13379                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13380                                         } else if (locals_var->opcode == OP_REGVAR) {
13381                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13382                                         } else {
13383                                                 g_assert_not_reached ();
13384                                         }
13385                                         /* Compute the address */
13386                                         ins->opcode = OP_PADD;
13387                                         ins->sreg1 = reg3;
13388                                         ins->sreg2 = reg2;
13389
13390                                         mono_bblock_insert_before_ins (bb, ins, load3);
13391                                         mono_bblock_insert_before_ins (bb, load3, load2);
13392                                         if (load)
13393                                                 mono_bblock_insert_before_ins (bb, load2, load);
13394                                 } else {
13395                                         g_assert (var->opcode == OP_REGOFFSET);
13396
13397                                         ins->opcode = OP_ADD_IMM;
13398                                         ins->sreg1 = var->inst_basereg;
13399                                         ins->inst_imm = var->inst_offset;
13400                                 }
13401
13402                                 *need_local_opts = TRUE;
13403                                 spec = INS_INFO (ins->opcode);
13404                         }
13405
13406                         if (ins->opcode < MONO_CEE_LAST) {
13407                                 mono_print_ins (ins);
13408                                 g_assert_not_reached ();
13409                         }
13410
13411                         /*
13412                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13413                          * src register.
13414                          * FIXME:
13415                          */
13416                         if (MONO_IS_STORE_MEMBASE (ins)) {
13417                                 tmp_reg = ins->dreg;
13418                                 ins->dreg = ins->sreg2;
13419                                 ins->sreg2 = tmp_reg;
13420                                 store = TRUE;
13421
13422                                 spec2 [MONO_INST_DEST] = ' ';
13423                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13424                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13425                                 spec2 [MONO_INST_SRC3] = ' ';
13426                                 spec = spec2;
13427                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13428                                 g_assert_not_reached ();
13429                         else
13430                                 store = FALSE;
13431                         no_lvreg = FALSE;
13432
13433                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13434                                 printf ("\t %.3s %d", spec, ins->dreg);
13435                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13436                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13437                                         printf (" %d", sregs [srcindex]);
13438                                 printf ("\n");
13439                         }
13440
13441                         /***************/
13442                         /*    DREG     */
13443                         /***************/
13444                         regtype = spec [MONO_INST_DEST];
13445                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13446                         prev_dreg = -1;
13447
13448                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13449                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13450                                 MonoInst *store_ins;
13451                                 int store_opcode;
13452                                 MonoInst *def_ins = ins;
13453                                 int dreg = ins->dreg; /* The original vreg */
13454
13455                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13456
13457                                 if (var->opcode == OP_REGVAR) {
13458                                         ins->dreg = var->dreg;
13459                                 } 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)) {
13460                                         /* 
13461                                          * Instead of emitting a load+store, use a _membase opcode.
13462                                          */
13463                                         g_assert (var->opcode == OP_REGOFFSET);
13464                                         if (ins->opcode == OP_MOVE) {
13465                                                 NULLIFY_INS (ins);
13466                                                 def_ins = NULL;
13467                                         } else {
13468                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13469                                                 ins->inst_basereg = var->inst_basereg;
13470                                                 ins->inst_offset = var->inst_offset;
13471                                                 ins->dreg = -1;
13472                                         }
13473                                         spec = INS_INFO (ins->opcode);
13474                                 } else {
13475                                         guint32 lvreg;
13476
13477                                         g_assert (var->opcode == OP_REGOFFSET);
13478
13479                                         prev_dreg = ins->dreg;
13480
13481                                         /* Invalidate any previous lvreg for this vreg */
13482                                         vreg_to_lvreg [ins->dreg] = 0;
13483
13484                                         lvreg = 0;
13485
13486                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13487                                                 regtype = 'l';
13488                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13489                                         }
13490
13491                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13492
13493 #if SIZEOF_REGISTER != 8
13494                                         if (regtype == 'l') {
13495                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13496                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13497                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13498                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13499                                                 def_ins = store_ins;
13500                                         }
13501                                         else
13502 #endif
13503                                         {
13504                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13505
13506                                                 /* Try to fuse the store into the instruction itself */
13507                                                 /* FIXME: Add more instructions */
13508                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13509                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13510                                                         ins->inst_imm = ins->inst_c0;
13511                                                         ins->inst_destbasereg = var->inst_basereg;
13512                                                         ins->inst_offset = var->inst_offset;
13513                                                         spec = INS_INFO (ins->opcode);
13514                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13515                                                         ins->opcode = store_opcode;
13516                                                         ins->inst_destbasereg = var->inst_basereg;
13517                                                         ins->inst_offset = var->inst_offset;
13518
13519                                                         no_lvreg = TRUE;
13520
13521                                                         tmp_reg = ins->dreg;
13522                                                         ins->dreg = ins->sreg2;
13523                                                         ins->sreg2 = tmp_reg;
13524                                                         store = TRUE;
13525
13526                                                         spec2 [MONO_INST_DEST] = ' ';
13527                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13528                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13529                                                         spec2 [MONO_INST_SRC3] = ' ';
13530                                                         spec = spec2;
13531                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13532                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13533                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13534                                                         ins->dreg = -1;
13535                                                         ins->inst_basereg = var->inst_basereg;
13536                                                         ins->inst_offset = var->inst_offset;
13537                                                         spec = INS_INFO (ins->opcode);
13538                                                 } else {
13539                                                         /* printf ("INS: "); mono_print_ins (ins); */
13540                                                         /* Create a store instruction */
13541                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13542
13543                                                         /* Insert it after the instruction */
13544                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13545
13546                                                         def_ins = store_ins;
13547
13548                                                         /* 
13549                                                          * We can't assign ins->dreg to var->dreg here, since the
13550                                                          * sregs could use it. So set a flag, and do it after
13551                                                          * the sregs.
13552                                                          */
13553                                                         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)))
13554                                                                 dest_has_lvreg = TRUE;
13555                                                 }
13556                                         }
13557                                 }
13558
13559                                 if (def_ins && !live_range_start [dreg]) {
13560                                         live_range_start [dreg] = def_ins;
13561                                         live_range_start_bb [dreg] = bb;
13562                                 }
13563
13564                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13565                                         MonoInst *tmp;
13566
13567                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13568                                         tmp->inst_c1 = dreg;
13569                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13570                                 }
13571                         }
13572
13573                         /************/
13574                         /*  SREGS   */
13575                         /************/
13576                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13577                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13578                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13579                                 sreg = sregs [srcindex];
13580
13581                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13582                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13583                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13584                                         MonoInst *use_ins = ins;
13585                                         MonoInst *load_ins;
13586                                         guint32 load_opcode;
13587
13588                                         if (var->opcode == OP_REGVAR) {
13589                                                 sregs [srcindex] = var->dreg;
13590                                                 //mono_inst_set_src_registers (ins, sregs);
13591                                                 live_range_end [sreg] = use_ins;
13592                                                 live_range_end_bb [sreg] = bb;
13593
13594                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13595                                                         MonoInst *tmp;
13596
13597                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13598                                                         /* var->dreg is a hreg */
13599                                                         tmp->inst_c1 = sreg;
13600                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13601                                                 }
13602
13603                                                 continue;
13604                                         }
13605
13606                                         g_assert (var->opcode == OP_REGOFFSET);
13607                                                 
13608                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13609
13610                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13611
13612                                         if (vreg_to_lvreg [sreg]) {
13613                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13614
13615                                                 /* The variable is already loaded to an lvreg */
13616                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13617                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13618                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13619                                                 //mono_inst_set_src_registers (ins, sregs);
13620                                                 continue;
13621                                         }
13622
13623                                         /* Try to fuse the load into the instruction */
13624                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13625                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13626                                                 sregs [0] = var->inst_basereg;
13627                                                 //mono_inst_set_src_registers (ins, sregs);
13628                                                 ins->inst_offset = var->inst_offset;
13629                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13630                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13631                                                 sregs [1] = var->inst_basereg;
13632                                                 //mono_inst_set_src_registers (ins, sregs);
13633                                                 ins->inst_offset = var->inst_offset;
13634                                         } else {
13635                                                 if (MONO_IS_REAL_MOVE (ins)) {
13636                                                         ins->opcode = OP_NOP;
13637                                                         sreg = ins->dreg;
13638                                                 } else {
13639                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13640
13641                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13642
13643                                                         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) {
13644                                                                 if (var->dreg == prev_dreg) {
13645                                                                         /*
13646                                                                          * sreg refers to the value loaded by the load
13647                                                                          * emitted below, but we need to use ins->dreg
13648                                                                          * since it refers to the store emitted earlier.
13649                                                                          */
13650                                                                         sreg = ins->dreg;
13651                                                                 }
13652                                                                 g_assert (sreg != -1);
13653                                                                 vreg_to_lvreg [var->dreg] = sreg;
13654                                                                 g_assert (lvregs_len < 1024);
13655                                                                 lvregs [lvregs_len ++] = var->dreg;
13656                                                         }
13657                                                 }
13658
13659                                                 sregs [srcindex] = sreg;
13660                                                 //mono_inst_set_src_registers (ins, sregs);
13661
13662 #if SIZEOF_REGISTER != 8
13663                                                 if (regtype == 'l') {
13664                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13665                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13666                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13667                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13668                                                         use_ins = load_ins;
13669                                                 }
13670                                                 else
13671 #endif
13672                                                 {
13673 #if SIZEOF_REGISTER == 4
13674                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13675 #endif
13676                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13677                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13678                                                         use_ins = load_ins;
13679                                                 }
13680                                         }
13681
13682                                         if (var->dreg < orig_next_vreg) {
13683                                                 live_range_end [var->dreg] = use_ins;
13684                                                 live_range_end_bb [var->dreg] = bb;
13685                                         }
13686
13687                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13688                                                 MonoInst *tmp;
13689
13690                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13691                                                 tmp->inst_c1 = var->dreg;
13692                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13693                                         }
13694                                 }
13695                         }
13696                         mono_inst_set_src_registers (ins, sregs);
13697
13698                         if (dest_has_lvreg) {
13699                                 g_assert (ins->dreg != -1);
13700                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13701                                 g_assert (lvregs_len < 1024);
13702                                 lvregs [lvregs_len ++] = prev_dreg;
13703                                 dest_has_lvreg = FALSE;
13704                         }
13705
13706                         if (store) {
13707                                 tmp_reg = ins->dreg;
13708                                 ins->dreg = ins->sreg2;
13709                                 ins->sreg2 = tmp_reg;
13710                         }
13711
13712                         if (MONO_IS_CALL (ins)) {
13713                                 /* Clear vreg_to_lvreg array */
13714                                 for (i = 0; i < lvregs_len; i++)
13715                                         vreg_to_lvreg [lvregs [i]] = 0;
13716                                 lvregs_len = 0;
13717                         } else if (ins->opcode == OP_NOP) {
13718                                 ins->dreg = -1;
13719                                 MONO_INST_NULLIFY_SREGS (ins);
13720                         }
13721
13722                         if (cfg->verbose_level > 2)
13723                                 mono_print_ins_index (1, ins);
13724                 }
13725
13726                 /* Extend the live range based on the liveness info */
13727                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13728                         for (i = 0; i < cfg->num_varinfo; i ++) {
13729                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13730
13731                                 if (vreg_is_volatile (cfg, vi->vreg))
13732                                         /* The liveness info is incomplete */
13733                                         continue;
13734
13735                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13736                                         /* Live from at least the first ins of this bb */
13737                                         live_range_start [vi->vreg] = bb->code;
13738                                         live_range_start_bb [vi->vreg] = bb;
13739                                 }
13740
13741                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13742                                         /* Live at least until the last ins of this bb */
13743                                         live_range_end [vi->vreg] = bb->last_ins;
13744                                         live_range_end_bb [vi->vreg] = bb;
13745                                 }
13746                         }
13747                 }
13748         }
13749         
13750 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13751         /*
13752          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13753          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13754          */
13755         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13756                 for (i = 0; i < cfg->num_varinfo; ++i) {
13757                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13758                         MonoInst *ins;
13759
13760                         if (live_range_start [vreg]) {
13761                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13762                                 ins->inst_c0 = i;
13763                                 ins->inst_c1 = vreg;
13764                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13765                         }
13766                         if (live_range_end [vreg]) {
13767                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13768                                 ins->inst_c0 = i;
13769                                 ins->inst_c1 = vreg;
13770                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13771                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13772                                 else
13773                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13774                         }
13775                 }
13776         }
13777 #endif
13778
13779         if (cfg->gsharedvt_locals_var_ins) {
13780                 /* Nullify if unused */
13781                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13782                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13783         }
13784
13785         g_free (live_range_start);
13786         g_free (live_range_end);
13787         g_free (live_range_start_bb);
13788         g_free (live_range_end_bb);
13789 }
13790
13791 /**
13792  * FIXME:
13793  * - use 'iadd' instead of 'int_add'
13794  * - handling ovf opcodes: decompose in method_to_ir.
13795  * - unify iregs/fregs
13796  *   -> partly done, the missing parts are:
13797  *   - a more complete unification would involve unifying the hregs as well, so
13798  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13799  *     would no longer map to the machine hregs, so the code generators would need to
13800  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13801  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13802  *     fp/non-fp branches speeds it up by about 15%.
13803  * - use sext/zext opcodes instead of shifts
13804  * - add OP_ICALL
13805  * - get rid of TEMPLOADs if possible and use vregs instead
13806  * - clean up usage of OP_P/OP_ opcodes
13807  * - cleanup usage of DUMMY_USE
13808  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13809  *   stack
13810  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13811  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13812  * - make sure handle_stack_args () is called before the branch is emitted
13813  * - when the new IR is done, get rid of all unused stuff
13814  * - COMPARE/BEQ as separate instructions or unify them ?
13815  *   - keeping them separate allows specialized compare instructions like
13816  *     compare_imm, compare_membase
13817  *   - most back ends unify fp compare+branch, fp compare+ceq
13818  * - integrate mono_save_args into inline_method
13819  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13820  * - handle long shift opts on 32 bit platforms somehow: they require 
13821  *   3 sregs (2 for arg1 and 1 for arg2)
13822  * - make byref a 'normal' type.
13823  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13824  *   variable if needed.
13825  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13826  *   like inline_method.
13827  * - remove inlining restrictions
13828  * - fix LNEG and enable cfold of INEG
13829  * - generalize x86 optimizations like ldelema as a peephole optimization
13830  * - add store_mem_imm for amd64
13831  * - optimize the loading of the interruption flag in the managed->native wrappers
13832  * - avoid special handling of OP_NOP in passes
13833  * - move code inserting instructions into one function/macro.
13834  * - try a coalescing phase after liveness analysis
13835  * - add float -> vreg conversion + local optimizations on !x86
13836  * - figure out how to handle decomposed branches during optimizations, ie.
13837  *   compare+branch, op_jump_table+op_br etc.
13838  * - promote RuntimeXHandles to vregs
13839  * - vtype cleanups:
13840  *   - add a NEW_VARLOADA_VREG macro
13841  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13842  *   accessing vtype fields.
13843  * - get rid of I8CONST on 64 bit platforms
13844  * - dealing with the increase in code size due to branches created during opcode
13845  *   decomposition:
13846  *   - use extended basic blocks
13847  *     - all parts of the JIT
13848  *     - handle_global_vregs () && local regalloc
13849  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13850  * - sources of increase in code size:
13851  *   - vtypes
13852  *   - long compares
13853  *   - isinst and castclass
13854  *   - lvregs not allocated to global registers even if used multiple times
13855  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13856  *   meaningful.
13857  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13858  * - add all micro optimizations from the old JIT
13859  * - put tree optimizations into the deadce pass
13860  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13861  *   specific function.
13862  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13863  *   fcompare + branchCC.
13864  * - create a helper function for allocating a stack slot, taking into account 
13865  *   MONO_CFG_HAS_SPILLUP.
13866  * - merge r68207.
13867  * - merge the ia64 switch changes.
13868  * - optimize mono_regstate2_alloc_int/float.
13869  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13870  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13871  *   parts of the tree could be separated by other instructions, killing the tree
13872  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13873  *   instructions if the result of the load is used multiple times ?
13874  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13875  * - LAST MERGE: 108395.
13876  * - when returning vtypes in registers, generate IR and append it to the end of the
13877  *   last bb instead of doing it in the epilog.
13878  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13879  */
13880
13881 /*
13882
13883 NOTES
13884 -----
13885
13886 - When to decompose opcodes:
13887   - earlier: this makes some optimizations hard to implement, since the low level IR
13888   no longer contains the neccessary information. But it is easier to do.
13889   - later: harder to implement, enables more optimizations.
13890 - Branches inside bblocks:
13891   - created when decomposing complex opcodes. 
13892     - branches to another bblock: harmless, but not tracked by the branch 
13893       optimizations, so need to branch to a label at the start of the bblock.
13894     - branches to inside the same bblock: very problematic, trips up the local
13895       reg allocator. Can be fixed by spitting the current bblock, but that is a
13896       complex operation, since some local vregs can become global vregs etc.
13897 - Local/global vregs:
13898   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13899     local register allocator.
13900   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13901     structure, created by mono_create_var (). Assigned to hregs or the stack by
13902     the global register allocator.
13903 - When to do optimizations like alu->alu_imm:
13904   - earlier -> saves work later on since the IR will be smaller/simpler
13905   - later -> can work on more instructions
13906 - Handling of valuetypes:
13907   - When a vtype is pushed on the stack, a new temporary is created, an 
13908     instruction computing its address (LDADDR) is emitted and pushed on
13909     the stack. Need to optimize cases when the vtype is used immediately as in
13910     argument passing, stloc etc.
13911 - Instead of the to_end stuff in the old JIT, simply call the function handling
13912   the values on the stack before emitting the last instruction of the bb.
13913 */
13914
13915 #endif /* DISABLE_JIT */