[jit] Optimize the managed allocator fastpath
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/gc-internal.h>
53 #include <mono/metadata/security-manager.h>
54 #include <mono/metadata/threads-types.h>
55 #include <mono/metadata/security-core-clr.h>
56 #include <mono/metadata/monitor.h>
57 #include <mono/metadata/profiler-private.h>
58 #include <mono/metadata/profiler.h>
59 #include <mono/metadata/debug-mono-symfile.h>
60 #include <mono/utils/mono-compiler.h>
61 #include <mono/utils/mono-memory-model.h>
62 #include <mono/metadata/mono-basic-block.h>
63
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71 #include "seq-points.h"
72
73 #define BRANCH_COST 10
74 #define INLINE_LENGTH_LIMIT 20
75
76 /* These have 'cfg' as an implicit argument */
77 #define INLINE_FAILURE(msg) do {                                                                        \
78         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
79                 inline_failure (cfg, msg);                                                                              \
80                 goto exception_exit;                                                                                    \
81         } \
82         } while (0)
83 #define CHECK_CFG_EXCEPTION do {\
84                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
85                         goto exception_exit;                                            \
86         } while (0)
87 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
88                 method_access_failure ((cfg), (method), (cmethod));                     \
89                 goto exception_exit;                                                                            \
90         } while (0)
91 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
92                 field_access_failure ((cfg), (method), (field));                        \
93                 goto exception_exit;    \
94         } while (0)
95 #define GENERIC_SHARING_FAILURE(opcode) do {            \
96                 if (cfg->gshared) {                                                                     \
97                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define GSHAREDVT_FAILURE(opcode) do {          \
102         if (cfg->gsharedvt) {                                                                                           \
103                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
104                 goto exception_exit;                                                                                    \
105         }                                                                                                                                       \
106         } while (0)
107 #define OUT_OF_MEMORY_FAILURE do {      \
108                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
109                 goto exception_exit;    \
110         } while (0)
111 #define DISABLE_AOT(cfg) do { \
112                 if ((cfg)->verbose_level >= 2)                                            \
113                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
114                 (cfg)->disable_aot = TRUE;                                                        \
115         } while (0)
116 #define LOAD_ERROR do { \
117                 break_on_unverified ();                                                         \
118                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
119                 goto exception_exit;                                                                    \
120         } while (0)
121
122 #define TYPE_LOAD_ERROR(klass) do { \
123                 cfg->exception_ptr = klass; \
124                 LOAD_ERROR;                                     \
125         } while (0)
126
127 #define CHECK_CFG_ERROR do {\
128                 if (!mono_error_ok (&cfg->error)) { \
129                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
130                         goto mono_error_exit; \
131                 } \
132         } while (0)
133
134 /* Determine whenever 'ins' represents a load of the 'this' argument */
135 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
136
137 static int ldind_to_load_membase (int opcode);
138 static int stind_to_store_membase (int opcode);
139
140 int mono_op_to_op_imm (int opcode);
141 int mono_op_to_op_imm_noemul (int opcode);
142
143 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
144
145 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
146                                                   guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb);
147
148 /* helper methods signatures */
149 static MonoMethodSignature *helper_sig_class_init_trampoline;
150 static MonoMethodSignature *helper_sig_domain_get;
151 static MonoMethodSignature *helper_sig_generic_class_init_trampoline;
152 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm;
153 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
154 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline;
155 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm;
156 static MonoMethodSignature *helper_sig_monitor_enter_v4_trampoline_llvm;
157
158 /*
159  * Instruction metadata
160  */
161 #ifdef MINI_OP
162 #undef MINI_OP
163 #endif
164 #ifdef MINI_OP3
165 #undef MINI_OP3
166 #endif
167 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
168 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
169 #define NONE ' '
170 #define IREG 'i'
171 #define FREG 'f'
172 #define VREG 'v'
173 #define XREG 'x'
174 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
175 #define LREG IREG
176 #else
177 #define LREG 'l'
178 #endif
179 /* keep in sync with the enum in mini.h */
180 const char
181 ins_info[] = {
182 #include "mini-ops.h"
183 };
184 #undef MINI_OP
185 #undef MINI_OP3
186
187 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
188 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
189 /* 
190  * This should contain the index of the last sreg + 1. This is not the same
191  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
192  */
193 const gint8 ins_sreg_counts[] = {
194 #include "mini-ops.h"
195 };
196 #undef MINI_OP
197 #undef MINI_OP3
198
199 #define MONO_INIT_VARINFO(vi,id) do { \
200         (vi)->range.first_use.pos.bid = 0xffff; \
201         (vi)->reg = -1; \
202         (vi)->idx = (id); \
203 } while (0)
204
205 guint32
206 mono_alloc_ireg (MonoCompile *cfg)
207 {
208         return alloc_ireg (cfg);
209 }
210
211 guint32
212 mono_alloc_lreg (MonoCompile *cfg)
213 {
214         return alloc_lreg (cfg);
215 }
216
217 guint32
218 mono_alloc_freg (MonoCompile *cfg)
219 {
220         return alloc_freg (cfg);
221 }
222
223 guint32
224 mono_alloc_preg (MonoCompile *cfg)
225 {
226         return alloc_preg (cfg);
227 }
228
229 guint32
230 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
231 {
232         return alloc_dreg (cfg, stack_type);
233 }
234
235 /*
236  * mono_alloc_ireg_ref:
237  *
238  *   Allocate an IREG, and mark it as holding a GC ref.
239  */
240 guint32
241 mono_alloc_ireg_ref (MonoCompile *cfg)
242 {
243         return alloc_ireg_ref (cfg);
244 }
245
246 /*
247  * mono_alloc_ireg_mp:
248  *
249  *   Allocate an IREG, and mark it as holding a managed pointer.
250  */
251 guint32
252 mono_alloc_ireg_mp (MonoCompile *cfg)
253 {
254         return alloc_ireg_mp (cfg);
255 }
256
257 /*
258  * mono_alloc_ireg_copy:
259  *
260  *   Allocate an IREG with the same GC type as VREG.
261  */
262 guint32
263 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
264 {
265         if (vreg_is_ref (cfg, vreg))
266                 return alloc_ireg_ref (cfg);
267         else if (vreg_is_mp (cfg, vreg))
268                 return alloc_ireg_mp (cfg);
269         else
270                 return alloc_ireg (cfg);
271 }
272
273 guint
274 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
275 {
276         if (type->byref)
277                 return OP_MOVE;
278
279         type = mini_replace_type (type);
280 handle_enum:
281         switch (type->type) {
282         case MONO_TYPE_I1:
283         case MONO_TYPE_U1:
284         case MONO_TYPE_BOOLEAN:
285                 return OP_MOVE;
286         case MONO_TYPE_I2:
287         case MONO_TYPE_U2:
288         case MONO_TYPE_CHAR:
289                 return OP_MOVE;
290         case MONO_TYPE_I4:
291         case MONO_TYPE_U4:
292                 return OP_MOVE;
293         case MONO_TYPE_I:
294         case MONO_TYPE_U:
295         case MONO_TYPE_PTR:
296         case MONO_TYPE_FNPTR:
297                 return OP_MOVE;
298         case MONO_TYPE_CLASS:
299         case MONO_TYPE_STRING:
300         case MONO_TYPE_OBJECT:
301         case MONO_TYPE_SZARRAY:
302         case MONO_TYPE_ARRAY:    
303                 return OP_MOVE;
304         case MONO_TYPE_I8:
305         case MONO_TYPE_U8:
306 #if SIZEOF_REGISTER == 8
307                 return OP_MOVE;
308 #else
309                 return OP_LMOVE;
310 #endif
311         case MONO_TYPE_R4:
312                 return OP_FMOVE;
313         case MONO_TYPE_R8:
314                 return OP_FMOVE;
315         case MONO_TYPE_VALUETYPE:
316                 if (type->data.klass->enumtype) {
317                         type = mono_class_enum_basetype (type->data.klass);
318                         goto handle_enum;
319                 }
320                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
321                         return OP_XMOVE;
322                 return OP_VMOVE;
323         case MONO_TYPE_TYPEDBYREF:
324                 return OP_VMOVE;
325         case MONO_TYPE_GENERICINST:
326                 type = &type->data.generic_class->container_class->byval_arg;
327                 goto handle_enum;
328         case MONO_TYPE_VAR:
329         case MONO_TYPE_MVAR:
330                 g_assert (cfg->generic_sharing_context);
331                 if (mini_type_var_is_vt (cfg, type))
332                         return OP_VMOVE;
333                 else
334                         return OP_MOVE;
335         default:
336                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
337         }
338         return -1;
339 }
340
341 void
342 mono_print_bb (MonoBasicBlock *bb, const char *msg)
343 {
344         int i;
345         MonoInst *tree;
346
347         printf ("\n%s %d: [IN: ", msg, bb->block_num);
348         for (i = 0; i < bb->in_count; ++i)
349                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
350         printf (", OUT: ");
351         for (i = 0; i < bb->out_count; ++i)
352                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
353         printf (" ]\n");
354         for (tree = bb->code; tree; tree = tree->next)
355                 mono_print_ins_index (-1, tree);
356 }
357
358 void
359 mono_create_helper_signatures (void)
360 {
361         helper_sig_domain_get = mono_create_icall_signature ("ptr");
362         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
363         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
364         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
365         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
366         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
367         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
368         helper_sig_monitor_enter_v4_trampoline_llvm = mono_create_icall_signature ("void object ptr");
369 }
370
371 static MONO_NEVER_INLINE void
372 break_on_unverified (void)
373 {
374         if (mini_get_debug_options ()->break_on_unverified)
375                 G_BREAKPOINT ();
376 }
377
378 static MONO_NEVER_INLINE void
379 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
380 {
381         char *method_fname = mono_method_full_name (method, TRUE);
382         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
383         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
384         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
385         g_free (method_fname);
386         g_free (cil_method_fname);
387 }
388
389 static MONO_NEVER_INLINE void
390 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
391 {
392         char *method_fname = mono_method_full_name (method, TRUE);
393         char *field_fname = mono_field_full_name (field);
394         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
395         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
396         g_free (method_fname);
397         g_free (field_fname);
398 }
399
400 static MONO_NEVER_INLINE void
401 inline_failure (MonoCompile *cfg, const char *msg)
402 {
403         if (cfg->verbose_level >= 2)
404                 printf ("inline failed: %s\n", msg);
405         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
406 }
407
408 static MONO_NEVER_INLINE void
409 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
410 {
411         if (cfg->verbose_level > 2)                                                                                     \
412                 printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), __LINE__);
413         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
414 }
415
416 static MONO_NEVER_INLINE void
417 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
418 {
419         cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", cfg->current_method->klass->name_space, cfg->current_method->klass->name, cfg->current_method->name, cfg->current_method->signature->param_count, mono_opcode_name ((opcode)), file, line);
420         if (cfg->verbose_level >= 2)
421                 printf ("%s\n", cfg->exception_message);
422         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
423 }
424
425 /*
426  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
427  * foo<T> (int i) { ldarg.0; box T; }
428  */
429 #define UNVERIFIED do { \
430         if (cfg->gsharedvt) { \
431                 if (cfg->verbose_level > 2)                                                                     \
432                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
433                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
434                 goto exception_exit;                                                                                    \
435         }                                                                                                                                       \
436         break_on_unverified ();                                                                                         \
437         goto unverified;                                                                                                        \
438 } while (0)
439
440 #define GET_BBLOCK(cfg,tblock,ip) do {  \
441                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
442                 if (!(tblock)) {        \
443                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
444             NEW_BBLOCK (cfg, (tblock)); \
445                         (tblock)->cil_code = (ip);      \
446                         ADD_BBLOCK (cfg, (tblock));     \
447                 } \
448         } while (0)
449
450 #if defined(TARGET_X86) || defined(TARGET_AMD64)
451 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
452                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
453                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
454                 (dest)->sreg1 = (sr1); \
455                 (dest)->sreg2 = (sr2); \
456                 (dest)->inst_imm = (imm); \
457                 (dest)->backend.shift_amount = (shift); \
458                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
459         } while (0)
460 #endif
461
462 #if SIZEOF_REGISTER == 8
463 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
464                 /* FIXME: Need to add many more cases */ \
465                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
466                         MonoInst *widen; \
467                         int dr = alloc_preg (cfg); \
468                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
469                         (ins)->sreg2 = widen->dreg; \
470                 } \
471         } while (0)
472 #else
473 #define ADD_WIDEN_OP(ins, arg1, arg2)
474 #endif
475
476 #define ADD_BINOP(op) do {      \
477                 MONO_INST_NEW (cfg, ins, (op)); \
478                 sp -= 2;        \
479                 ins->sreg1 = sp [0]->dreg;      \
480                 ins->sreg2 = sp [1]->dreg;      \
481                 type_from_op (ins, sp [0], sp [1]);     \
482                 CHECK_TYPE (ins);       \
483                 /* Have to insert a widening op */               \
484         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
485         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
486         MONO_ADD_INS ((cfg)->cbb, (ins)); \
487         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
488         } while (0)
489
490 #define ADD_UNOP(op) do {       \
491                 MONO_INST_NEW (cfg, ins, (op)); \
492                 sp--;   \
493                 ins->sreg1 = sp [0]->dreg;      \
494                 type_from_op (ins, sp [0], NULL);       \
495                 CHECK_TYPE (ins);       \
496         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
497         MONO_ADD_INS ((cfg)->cbb, (ins)); \
498                 *sp++ = mono_decompose_opcode (cfg, ins); \
499         } while (0)
500
501 #define ADD_BINCOND(next_block) do {    \
502                 MonoInst *cmp;  \
503                 sp -= 2; \
504                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
505                 cmp->sreg1 = sp [0]->dreg;      \
506                 cmp->sreg2 = sp [1]->dreg;      \
507                 type_from_op (cmp, sp [0], sp [1]);     \
508                 CHECK_TYPE (cmp);       \
509                 type_from_op (ins, sp [0], sp [1]);     \
510                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
511                 GET_BBLOCK (cfg, tblock, target);               \
512                 link_bblock (cfg, bblock, tblock);      \
513                 ins->inst_true_bb = tblock;     \
514                 if ((next_block)) {     \
515                         link_bblock (cfg, bblock, (next_block));        \
516                         ins->inst_false_bb = (next_block);      \
517                         start_new_bblock = 1;   \
518                 } else {        \
519                         GET_BBLOCK (cfg, tblock, ip);           \
520                         link_bblock (cfg, bblock, tblock);      \
521                         ins->inst_false_bb = tblock;    \
522                         start_new_bblock = 2;   \
523                 }       \
524                 if (sp != stack_start) {                                                                        \
525                     handle_stack_args (cfg, stack_start, sp - stack_start); \
526                         CHECK_UNVERIFIABLE (cfg); \
527                 } \
528         MONO_ADD_INS (bblock, cmp); \
529                 MONO_ADD_INS (bblock, ins);     \
530         } while (0)
531
532 /* *
533  * link_bblock: Links two basic blocks
534  *
535  * links two basic blocks in the control flow graph, the 'from'
536  * argument is the starting block and the 'to' argument is the block
537  * the control flow ends to after 'from'.
538  */
539 static void
540 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
541 {
542         MonoBasicBlock **newa;
543         int i, found;
544
545 #if 0
546         if (from->cil_code) {
547                 if (to->cil_code)
548                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
549                 else
550                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
551         } else {
552                 if (to->cil_code)
553                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
554                 else
555                         printf ("edge from entry to exit\n");
556         }
557 #endif
558
559         found = FALSE;
560         for (i = 0; i < from->out_count; ++i) {
561                 if (to == from->out_bb [i]) {
562                         found = TRUE;
563                         break;
564                 }
565         }
566         if (!found) {
567                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
568                 for (i = 0; i < from->out_count; ++i) {
569                         newa [i] = from->out_bb [i];
570                 }
571                 newa [i] = to;
572                 from->out_count++;
573                 from->out_bb = newa;
574         }
575
576         found = FALSE;
577         for (i = 0; i < to->in_count; ++i) {
578                 if (from == to->in_bb [i]) {
579                         found = TRUE;
580                         break;
581                 }
582         }
583         if (!found) {
584                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
585                 for (i = 0; i < to->in_count; ++i) {
586                         newa [i] = to->in_bb [i];
587                 }
588                 newa [i] = from;
589                 to->in_count++;
590                 to->in_bb = newa;
591         }
592 }
593
594 void
595 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
596 {
597         link_bblock (cfg, from, to);
598 }
599
600 /**
601  * mono_find_block_region:
602  *
603  *   We mark each basic block with a region ID. We use that to avoid BB
604  *   optimizations when blocks are in different regions.
605  *
606  * Returns:
607  *   A region token that encodes where this region is, and information
608  *   about the clause owner for this block.
609  *
610  *   The region encodes the try/catch/filter clause that owns this block
611  *   as well as the type.  -1 is a special value that represents a block
612  *   that is in none of try/catch/filter.
613  */
614 static int
615 mono_find_block_region (MonoCompile *cfg, int offset)
616 {
617         MonoMethodHeader *header = cfg->header;
618         MonoExceptionClause *clause;
619         int i;
620
621         for (i = 0; i < header->num_clauses; ++i) {
622                 clause = &header->clauses [i];
623                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
624                     (offset < (clause->handler_offset)))
625                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
626                            
627                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
628                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
629                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
630                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
631                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
632                         else
633                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
634                 }
635
636                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
637                         return ((i + 1) << 8) | clause->flags;
638         }
639
640         return -1;
641 }
642
643 static GList*
644 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
645 {
646         MonoMethodHeader *header = cfg->header;
647         MonoExceptionClause *clause;
648         int i;
649         GList *res = NULL;
650
651         for (i = 0; i < header->num_clauses; ++i) {
652                 clause = &header->clauses [i];
653                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
654                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
655                         if (clause->flags == type)
656                                 res = g_list_append (res, clause);
657                 }
658         }
659         return res;
660 }
661
662 static void
663 mono_create_spvar_for_region (MonoCompile *cfg, int region)
664 {
665         MonoInst *var;
666
667         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
668         if (var)
669                 return;
670
671         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
672         /* prevent it from being register allocated */
673         var->flags |= MONO_INST_VOLATILE;
674
675         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
676 }
677
678 MonoInst *
679 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
680 {
681         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
682 }
683
684 static MonoInst*
685 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
686 {
687         MonoInst *var;
688
689         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
690         if (var)
691                 return var;
692
693         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
694         /* prevent it from being register allocated */
695         var->flags |= MONO_INST_VOLATILE;
696
697         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
698
699         return var;
700 }
701
702 /*
703  * Returns the type used in the eval stack when @type is loaded.
704  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
705  */
706 void
707 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
708 {
709         MonoClass *klass;
710
711         type = mini_replace_type (type);
712         inst->klass = klass = mono_class_from_mono_type (type);
713         if (type->byref) {
714                 inst->type = STACK_MP;
715                 return;
716         }
717
718 handle_enum:
719         switch (type->type) {
720         case MONO_TYPE_VOID:
721                 inst->type = STACK_INV;
722                 return;
723         case MONO_TYPE_I1:
724         case MONO_TYPE_U1:
725         case MONO_TYPE_BOOLEAN:
726         case MONO_TYPE_I2:
727         case MONO_TYPE_U2:
728         case MONO_TYPE_CHAR:
729         case MONO_TYPE_I4:
730         case MONO_TYPE_U4:
731                 inst->type = STACK_I4;
732                 return;
733         case MONO_TYPE_I:
734         case MONO_TYPE_U:
735         case MONO_TYPE_PTR:
736         case MONO_TYPE_FNPTR:
737                 inst->type = STACK_PTR;
738                 return;
739         case MONO_TYPE_CLASS:
740         case MONO_TYPE_STRING:
741         case MONO_TYPE_OBJECT:
742         case MONO_TYPE_SZARRAY:
743         case MONO_TYPE_ARRAY:    
744                 inst->type = STACK_OBJ;
745                 return;
746         case MONO_TYPE_I8:
747         case MONO_TYPE_U8:
748                 inst->type = STACK_I8;
749                 return;
750         case MONO_TYPE_R4:
751         case MONO_TYPE_R8:
752                 inst->type = STACK_R8;
753                 return;
754         case MONO_TYPE_VALUETYPE:
755                 if (type->data.klass->enumtype) {
756                         type = mono_class_enum_basetype (type->data.klass);
757                         goto handle_enum;
758                 } else {
759                         inst->klass = klass;
760                         inst->type = STACK_VTYPE;
761                         return;
762                 }
763         case MONO_TYPE_TYPEDBYREF:
764                 inst->klass = mono_defaults.typed_reference_class;
765                 inst->type = STACK_VTYPE;
766                 return;
767         case MONO_TYPE_GENERICINST:
768                 type = &type->data.generic_class->container_class->byval_arg;
769                 goto handle_enum;
770         case MONO_TYPE_VAR:
771         case MONO_TYPE_MVAR:
772                 g_assert (cfg->generic_sharing_context);
773                 if (mini_is_gsharedvt_type (cfg, type)) {
774                         g_assert (cfg->gsharedvt);
775                         inst->type = STACK_VTYPE;
776                 } else {
777                         inst->type = STACK_OBJ;
778                 }
779                 return;
780         default:
781                 g_error ("unknown type 0x%02x in eval stack type", type->type);
782         }
783 }
784
785 /*
786  * The following tables are used to quickly validate the IL code in type_from_op ().
787  */
788 static const char
789 bin_num_table [STACK_MAX] [STACK_MAX] = {
790         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
791         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
792         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
793         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
794         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
795         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
796         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
797         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
798 };
799
800 static const char 
801 neg_table [] = {
802         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
803 };
804
805 /* reduce the size of this table */
806 static const char
807 bin_int_table [STACK_MAX] [STACK_MAX] = {
808         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
809         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
810         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
811         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
812         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
813         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
814         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
816 };
817
818 static const char
819 bin_comp_table [STACK_MAX] [STACK_MAX] = {
820 /*      Inv i  L  p  F  &  O  vt */
821         {0},
822         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
823         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
824         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
825         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
826         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
827         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
828         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
829 };
830
831 /* reduce the size of this table */
832 static const char
833 shift_table [STACK_MAX] [STACK_MAX] = {
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
836         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
838         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
839         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
840         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
841         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
842 };
843
844 /*
845  * Tables to map from the non-specific opcode to the matching
846  * type-specific opcode.
847  */
848 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
849 static const guint16
850 binops_op_map [STACK_MAX] = {
851         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
852 };
853
854 /* handles from CEE_NEG to CEE_CONV_U8 */
855 static const guint16
856 unops_op_map [STACK_MAX] = {
857         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
858 };
859
860 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
861 static const guint16
862 ovfops_op_map [STACK_MAX] = {
863         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
864 };
865
866 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
867 static const guint16
868 ovf2ops_op_map [STACK_MAX] = {
869         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
870 };
871
872 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
873 static const guint16
874 ovf3ops_op_map [STACK_MAX] = {
875         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
876 };
877
878 /* handles from CEE_BEQ to CEE_BLT_UN */
879 static const guint16
880 beqops_op_map [STACK_MAX] = {
881         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
882 };
883
884 /* handles from CEE_CEQ to CEE_CLT_UN */
885 static const guint16
886 ceqops_op_map [STACK_MAX] = {
887         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
888 };
889
890 /*
891  * Sets ins->type (the type on the eval stack) according to the
892  * type of the opcode and the arguments to it.
893  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
894  *
895  * FIXME: this function sets ins->type unconditionally in some cases, but
896  * it should set it to invalid for some types (a conv.x on an object)
897  */
898 static void
899 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
900
901         switch (ins->opcode) {
902         /* binops */
903         case CEE_ADD:
904         case CEE_SUB:
905         case CEE_MUL:
906         case CEE_DIV:
907         case CEE_REM:
908                 /* FIXME: check unverifiable args for STACK_MP */
909                 ins->type = bin_num_table [src1->type] [src2->type];
910                 ins->opcode += binops_op_map [ins->type];
911                 break;
912         case CEE_DIV_UN:
913         case CEE_REM_UN:
914         case CEE_AND:
915         case CEE_OR:
916         case CEE_XOR:
917                 ins->type = bin_int_table [src1->type] [src2->type];
918                 ins->opcode += binops_op_map [ins->type];
919                 break;
920         case CEE_SHL:
921         case CEE_SHR:
922         case CEE_SHR_UN:
923                 ins->type = shift_table [src1->type] [src2->type];
924                 ins->opcode += binops_op_map [ins->type];
925                 break;
926         case OP_COMPARE:
927         case OP_LCOMPARE:
928         case OP_ICOMPARE:
929                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
930                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
931                         ins->opcode = OP_LCOMPARE;
932                 else if (src1->type == STACK_R8)
933                         ins->opcode = OP_FCOMPARE;
934                 else
935                         ins->opcode = OP_ICOMPARE;
936                 break;
937         case OP_ICOMPARE_IMM:
938                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
939                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
940                         ins->opcode = OP_LCOMPARE_IMM;          
941                 break;
942         case CEE_BEQ:
943         case CEE_BGE:
944         case CEE_BGT:
945         case CEE_BLE:
946         case CEE_BLT:
947         case CEE_BNE_UN:
948         case CEE_BGE_UN:
949         case CEE_BGT_UN:
950         case CEE_BLE_UN:
951         case CEE_BLT_UN:
952                 ins->opcode += beqops_op_map [src1->type];
953                 break;
954         case OP_CEQ:
955                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
956                 ins->opcode += ceqops_op_map [src1->type];
957                 break;
958         case OP_CGT:
959         case OP_CGT_UN:
960         case OP_CLT:
961         case OP_CLT_UN:
962                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
963                 ins->opcode += ceqops_op_map [src1->type];
964                 break;
965         /* unops */
966         case CEE_NEG:
967                 ins->type = neg_table [src1->type];
968                 ins->opcode += unops_op_map [ins->type];
969                 break;
970         case CEE_NOT:
971                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
972                         ins->type = src1->type;
973                 else
974                         ins->type = STACK_INV;
975                 ins->opcode += unops_op_map [ins->type];
976                 break;
977         case CEE_CONV_I1:
978         case CEE_CONV_I2:
979         case CEE_CONV_I4:
980         case CEE_CONV_U4:
981                 ins->type = STACK_I4;
982                 ins->opcode += unops_op_map [src1->type];
983                 break;
984         case CEE_CONV_R_UN:
985                 ins->type = STACK_R8;
986                 switch (src1->type) {
987                 case STACK_I4:
988                 case STACK_PTR:
989                         ins->opcode = OP_ICONV_TO_R_UN;
990                         break;
991                 case STACK_I8:
992                         ins->opcode = OP_LCONV_TO_R_UN; 
993                         break;
994                 }
995                 break;
996         case CEE_CONV_OVF_I1:
997         case CEE_CONV_OVF_U1:
998         case CEE_CONV_OVF_I2:
999         case CEE_CONV_OVF_U2:
1000         case CEE_CONV_OVF_I4:
1001         case CEE_CONV_OVF_U4:
1002                 ins->type = STACK_I4;
1003                 ins->opcode += ovf3ops_op_map [src1->type];
1004                 break;
1005         case CEE_CONV_OVF_I_UN:
1006         case CEE_CONV_OVF_U_UN:
1007                 ins->type = STACK_PTR;
1008                 ins->opcode += ovf2ops_op_map [src1->type];
1009                 break;
1010         case CEE_CONV_OVF_I1_UN:
1011         case CEE_CONV_OVF_I2_UN:
1012         case CEE_CONV_OVF_I4_UN:
1013         case CEE_CONV_OVF_U1_UN:
1014         case CEE_CONV_OVF_U2_UN:
1015         case CEE_CONV_OVF_U4_UN:
1016                 ins->type = STACK_I4;
1017                 ins->opcode += ovf2ops_op_map [src1->type];
1018                 break;
1019         case CEE_CONV_U:
1020                 ins->type = STACK_PTR;
1021                 switch (src1->type) {
1022                 case STACK_I4:
1023                         ins->opcode = OP_ICONV_TO_U;
1024                         break;
1025                 case STACK_PTR:
1026                 case STACK_MP:
1027 #if SIZEOF_VOID_P == 8
1028                         ins->opcode = OP_LCONV_TO_U;
1029 #else
1030                         ins->opcode = OP_MOVE;
1031 #endif
1032                         break;
1033                 case STACK_I8:
1034                         ins->opcode = OP_LCONV_TO_U;
1035                         break;
1036                 case STACK_R8:
1037                         ins->opcode = OP_FCONV_TO_U;
1038                         break;
1039                 }
1040                 break;
1041         case CEE_CONV_I8:
1042         case CEE_CONV_U8:
1043                 ins->type = STACK_I8;
1044                 ins->opcode += unops_op_map [src1->type];
1045                 break;
1046         case CEE_CONV_OVF_I8:
1047         case CEE_CONV_OVF_U8:
1048                 ins->type = STACK_I8;
1049                 ins->opcode += ovf3ops_op_map [src1->type];
1050                 break;
1051         case CEE_CONV_OVF_U8_UN:
1052         case CEE_CONV_OVF_I8_UN:
1053                 ins->type = STACK_I8;
1054                 ins->opcode += ovf2ops_op_map [src1->type];
1055                 break;
1056         case CEE_CONV_R4:
1057         case CEE_CONV_R8:
1058                 ins->type = STACK_R8;
1059                 ins->opcode += unops_op_map [src1->type];
1060                 break;
1061         case OP_CKFINITE:
1062                 ins->type = STACK_R8;           
1063                 break;
1064         case CEE_CONV_U2:
1065         case CEE_CONV_U1:
1066                 ins->type = STACK_I4;
1067                 ins->opcode += ovfops_op_map [src1->type];
1068                 break;
1069         case CEE_CONV_I:
1070         case CEE_CONV_OVF_I:
1071         case CEE_CONV_OVF_U:
1072                 ins->type = STACK_PTR;
1073                 ins->opcode += ovfops_op_map [src1->type];
1074                 break;
1075         case CEE_ADD_OVF:
1076         case CEE_ADD_OVF_UN:
1077         case CEE_MUL_OVF:
1078         case CEE_MUL_OVF_UN:
1079         case CEE_SUB_OVF:
1080         case CEE_SUB_OVF_UN:
1081                 ins->type = bin_num_table [src1->type] [src2->type];
1082                 ins->opcode += ovfops_op_map [src1->type];
1083                 if (ins->type == STACK_R8)
1084                         ins->type = STACK_INV;
1085                 break;
1086         case OP_LOAD_MEMBASE:
1087                 ins->type = STACK_PTR;
1088                 break;
1089         case OP_LOADI1_MEMBASE:
1090         case OP_LOADU1_MEMBASE:
1091         case OP_LOADI2_MEMBASE:
1092         case OP_LOADU2_MEMBASE:
1093         case OP_LOADI4_MEMBASE:
1094         case OP_LOADU4_MEMBASE:
1095                 ins->type = STACK_PTR;
1096                 break;
1097         case OP_LOADI8_MEMBASE:
1098                 ins->type = STACK_I8;
1099                 break;
1100         case OP_LOADR4_MEMBASE:
1101         case OP_LOADR8_MEMBASE:
1102                 ins->type = STACK_R8;
1103                 break;
1104         default:
1105                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1106                 break;
1107         }
1108
1109         if (ins->type == STACK_MP)
1110                 ins->klass = mono_defaults.object_class;
1111 }
1112
1113 static const char 
1114 ldind_type [] = {
1115         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1116 };
1117
1118 #if 0
1119
1120 static const char
1121 param_table [STACK_MAX] [STACK_MAX] = {
1122         {0},
1123 };
1124
1125 static int
1126 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1127         int i;
1128
1129         if (sig->hasthis) {
1130                 switch (args->type) {
1131                 case STACK_I4:
1132                 case STACK_I8:
1133                 case STACK_R8:
1134                 case STACK_VTYPE:
1135                 case STACK_INV:
1136                         return 0;
1137                 }
1138                 args++;
1139         }
1140         for (i = 0; i < sig->param_count; ++i) {
1141                 switch (args [i].type) {
1142                 case STACK_INV:
1143                         return 0;
1144                 case STACK_MP:
1145                         if (!sig->params [i]->byref)
1146                                 return 0;
1147                         continue;
1148                 case STACK_OBJ:
1149                         if (sig->params [i]->byref)
1150                                 return 0;
1151                         switch (sig->params [i]->type) {
1152                         case MONO_TYPE_CLASS:
1153                         case MONO_TYPE_STRING:
1154                         case MONO_TYPE_OBJECT:
1155                         case MONO_TYPE_SZARRAY:
1156                         case MONO_TYPE_ARRAY:
1157                                 break;
1158                         default:
1159                                 return 0;
1160                         }
1161                         continue;
1162                 case STACK_R8:
1163                         if (sig->params [i]->byref)
1164                                 return 0;
1165                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1166                                 return 0;
1167                         continue;
1168                 case STACK_PTR:
1169                 case STACK_I4:
1170                 case STACK_I8:
1171                 case STACK_VTYPE:
1172                         break;
1173                 }
1174                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1175                         return 0;*/
1176         }
1177         return 1;
1178 }
1179 #endif
1180
1181 /*
1182  * When we need a pointer to the current domain many times in a method, we
1183  * call mono_domain_get() once and we store the result in a local variable.
1184  * This function returns the variable that represents the MonoDomain*.
1185  */
1186 inline static MonoInst *
1187 mono_get_domainvar (MonoCompile *cfg)
1188 {
1189         if (!cfg->domainvar)
1190                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1191         return cfg->domainvar;
1192 }
1193
1194 /*
1195  * The got_var contains the address of the Global Offset Table when AOT 
1196  * compiling.
1197  */
1198 MonoInst *
1199 mono_get_got_var (MonoCompile *cfg)
1200 {
1201 #ifdef MONO_ARCH_NEED_GOT_VAR
1202         if (!cfg->compile_aot)
1203                 return NULL;
1204         if (!cfg->got_var) {
1205                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1206         }
1207         return cfg->got_var;
1208 #else
1209         return NULL;
1210 #endif
1211 }
1212
1213 static MonoInst *
1214 mono_get_vtable_var (MonoCompile *cfg)
1215 {
1216         g_assert (cfg->generic_sharing_context);
1217
1218         if (!cfg->rgctx_var) {
1219                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1220                 /* force the var to be stack allocated */
1221                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1222         }
1223
1224         return cfg->rgctx_var;
1225 }
1226
1227 static MonoType*
1228 type_from_stack_type (MonoInst *ins) {
1229         switch (ins->type) {
1230         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1231         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1232         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1233         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1234         case STACK_MP:
1235                 return &ins->klass->this_arg;
1236         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1237         case STACK_VTYPE: return &ins->klass->byval_arg;
1238         default:
1239                 g_error ("stack type %d to monotype not handled\n", ins->type);
1240         }
1241         return NULL;
1242 }
1243
1244 static G_GNUC_UNUSED int
1245 type_to_stack_type (MonoType *t)
1246 {
1247         t = mono_type_get_underlying_type (t);
1248         switch (t->type) {
1249         case MONO_TYPE_I1:
1250         case MONO_TYPE_U1:
1251         case MONO_TYPE_BOOLEAN:
1252         case MONO_TYPE_I2:
1253         case MONO_TYPE_U2:
1254         case MONO_TYPE_CHAR:
1255         case MONO_TYPE_I4:
1256         case MONO_TYPE_U4:
1257                 return STACK_I4;
1258         case MONO_TYPE_I:
1259         case MONO_TYPE_U:
1260         case MONO_TYPE_PTR:
1261         case MONO_TYPE_FNPTR:
1262                 return STACK_PTR;
1263         case MONO_TYPE_CLASS:
1264         case MONO_TYPE_STRING:
1265         case MONO_TYPE_OBJECT:
1266         case MONO_TYPE_SZARRAY:
1267         case MONO_TYPE_ARRAY:    
1268                 return STACK_OBJ;
1269         case MONO_TYPE_I8:
1270         case MONO_TYPE_U8:
1271                 return STACK_I8;
1272         case MONO_TYPE_R4:
1273         case MONO_TYPE_R8:
1274                 return STACK_R8;
1275         case MONO_TYPE_VALUETYPE:
1276         case MONO_TYPE_TYPEDBYREF:
1277                 return STACK_VTYPE;
1278         case MONO_TYPE_GENERICINST:
1279                 if (mono_type_generic_inst_is_valuetype (t))
1280                         return STACK_VTYPE;
1281                 else
1282                         return STACK_OBJ;
1283                 break;
1284         default:
1285                 g_assert_not_reached ();
1286         }
1287
1288         return -1;
1289 }
1290
1291 static MonoClass*
1292 array_access_to_klass (int opcode)
1293 {
1294         switch (opcode) {
1295         case CEE_LDELEM_U1:
1296                 return mono_defaults.byte_class;
1297         case CEE_LDELEM_U2:
1298                 return mono_defaults.uint16_class;
1299         case CEE_LDELEM_I:
1300         case CEE_STELEM_I:
1301                 return mono_defaults.int_class;
1302         case CEE_LDELEM_I1:
1303         case CEE_STELEM_I1:
1304                 return mono_defaults.sbyte_class;
1305         case CEE_LDELEM_I2:
1306         case CEE_STELEM_I2:
1307                 return mono_defaults.int16_class;
1308         case CEE_LDELEM_I4:
1309         case CEE_STELEM_I4:
1310                 return mono_defaults.int32_class;
1311         case CEE_LDELEM_U4:
1312                 return mono_defaults.uint32_class;
1313         case CEE_LDELEM_I8:
1314         case CEE_STELEM_I8:
1315                 return mono_defaults.int64_class;
1316         case CEE_LDELEM_R4:
1317         case CEE_STELEM_R4:
1318                 return mono_defaults.single_class;
1319         case CEE_LDELEM_R8:
1320         case CEE_STELEM_R8:
1321                 return mono_defaults.double_class;
1322         case CEE_LDELEM_REF:
1323         case CEE_STELEM_REF:
1324                 return mono_defaults.object_class;
1325         default:
1326                 g_assert_not_reached ();
1327         }
1328         return NULL;
1329 }
1330
1331 /*
1332  * We try to share variables when possible
1333  */
1334 static MonoInst *
1335 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1336 {
1337         MonoInst *res;
1338         int pos, vnum;
1339
1340         /* inlining can result in deeper stacks */ 
1341         if (slot >= cfg->header->max_stack)
1342                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1343
1344         pos = ins->type - 1 + slot * STACK_MAX;
1345
1346         switch (ins->type) {
1347         case STACK_I4:
1348         case STACK_I8:
1349         case STACK_R8:
1350         case STACK_PTR:
1351         case STACK_MP:
1352         case STACK_OBJ:
1353                 if ((vnum = cfg->intvars [pos]))
1354                         return cfg->varinfo [vnum];
1355                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1356                 cfg->intvars [pos] = res->inst_c0;
1357                 break;
1358         default:
1359                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1360         }
1361         return res;
1362 }
1363
1364 static void
1365 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1366 {
1367         /* 
1368          * Don't use this if a generic_context is set, since that means AOT can't
1369          * look up the method using just the image+token.
1370          * table == 0 means this is a reference made from a wrapper.
1371          */
1372         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1373                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1374                 jump_info_token->image = image;
1375                 jump_info_token->token = token;
1376                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1377         }
1378 }
1379
1380 /*
1381  * This function is called to handle items that are left on the evaluation stack
1382  * at basic block boundaries. What happens is that we save the values to local variables
1383  * and we reload them later when first entering the target basic block (with the
1384  * handle_loaded_temps () function).
1385  * A single joint point will use the same variables (stored in the array bb->out_stack or
1386  * bb->in_stack, if the basic block is before or after the joint point).
1387  *
1388  * This function needs to be called _before_ emitting the last instruction of
1389  * the bb (i.e. before emitting a branch).
1390  * If the stack merge fails at a join point, cfg->unverifiable is set.
1391  */
1392 static void
1393 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1394 {
1395         int i, bindex;
1396         MonoBasicBlock *bb = cfg->cbb;
1397         MonoBasicBlock *outb;
1398         MonoInst *inst, **locals;
1399         gboolean found;
1400
1401         if (!count)
1402                 return;
1403         if (cfg->verbose_level > 3)
1404                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1405         if (!bb->out_scount) {
1406                 bb->out_scount = count;
1407                 //printf ("bblock %d has out:", bb->block_num);
1408                 found = FALSE;
1409                 for (i = 0; i < bb->out_count; ++i) {
1410                         outb = bb->out_bb [i];
1411                         /* exception handlers are linked, but they should not be considered for stack args */
1412                         if (outb->flags & BB_EXCEPTION_HANDLER)
1413                                 continue;
1414                         //printf (" %d", outb->block_num);
1415                         if (outb->in_stack) {
1416                                 found = TRUE;
1417                                 bb->out_stack = outb->in_stack;
1418                                 break;
1419                         }
1420                 }
1421                 //printf ("\n");
1422                 if (!found) {
1423                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1424                         for (i = 0; i < count; ++i) {
1425                                 /* 
1426                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1427                                  * stack slot and if they are of the same type.
1428                                  * This won't cause conflicts since if 'local' is used to 
1429                                  * store one of the values in the in_stack of a bblock, then
1430                                  * the same variable will be used for the same outgoing stack 
1431                                  * slot as well. 
1432                                  * This doesn't work when inlining methods, since the bblocks
1433                                  * in the inlined methods do not inherit their in_stack from
1434                                  * the bblock they are inlined to. See bug #58863 for an
1435                                  * example.
1436                                  */
1437                                 if (cfg->inlined_method)
1438                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1439                                 else
1440                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1441                         }
1442                 }
1443         }
1444
1445         for (i = 0; i < bb->out_count; ++i) {
1446                 outb = bb->out_bb [i];
1447                 /* exception handlers are linked, but they should not be considered for stack args */
1448                 if (outb->flags & BB_EXCEPTION_HANDLER)
1449                         continue;
1450                 if (outb->in_scount) {
1451                         if (outb->in_scount != bb->out_scount) {
1452                                 cfg->unverifiable = TRUE;
1453                                 return;
1454                         }
1455                         continue; /* check they are the same locals */
1456                 }
1457                 outb->in_scount = count;
1458                 outb->in_stack = bb->out_stack;
1459         }
1460
1461         locals = bb->out_stack;
1462         cfg->cbb = bb;
1463         for (i = 0; i < count; ++i) {
1464                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1465                 inst->cil_code = sp [i]->cil_code;
1466                 sp [i] = locals [i];
1467                 if (cfg->verbose_level > 3)
1468                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1469         }
1470
1471         /*
1472          * It is possible that the out bblocks already have in_stack assigned, and
1473          * the in_stacks differ. In this case, we will store to all the different 
1474          * in_stacks.
1475          */
1476
1477         found = TRUE;
1478         bindex = 0;
1479         while (found) {
1480                 /* Find a bblock which has a different in_stack */
1481                 found = FALSE;
1482                 while (bindex < bb->out_count) {
1483                         outb = bb->out_bb [bindex];
1484                         /* exception handlers are linked, but they should not be considered for stack args */
1485                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1486                                 bindex++;
1487                                 continue;
1488                         }
1489                         if (outb->in_stack != locals) {
1490                                 for (i = 0; i < count; ++i) {
1491                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1492                                         inst->cil_code = sp [i]->cil_code;
1493                                         sp [i] = locals [i];
1494                                         if (cfg->verbose_level > 3)
1495                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1496                                 }
1497                                 locals = outb->in_stack;
1498                                 found = TRUE;
1499                                 break;
1500                         }
1501                         bindex ++;
1502                 }
1503         }
1504 }
1505
1506 /* Emit code which loads interface_offsets [klass->interface_id]
1507  * The array is stored in memory before vtable.
1508 */
1509 static void
1510 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1511 {
1512         if (cfg->compile_aot) {
1513                 int ioffset_reg = alloc_preg (cfg);
1514                 int iid_reg = alloc_preg (cfg);
1515
1516                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1517                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1518                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1519         }
1520         else {
1521                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1522         }
1523 }
1524
1525 static void
1526 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1527 {
1528         int ibitmap_reg = alloc_preg (cfg);
1529 #ifdef COMPRESSED_INTERFACE_BITMAP
1530         MonoInst *args [2];
1531         MonoInst *res, *ins;
1532         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1533         MONO_ADD_INS (cfg->cbb, ins);
1534         args [0] = ins;
1535         if (cfg->compile_aot)
1536                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1537         else
1538                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1539         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1540         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1541 #else
1542         int ibitmap_byte_reg = alloc_preg (cfg);
1543
1544         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1545
1546         if (cfg->compile_aot) {
1547                 int iid_reg = alloc_preg (cfg);
1548                 int shifted_iid_reg = alloc_preg (cfg);
1549                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1550                 int masked_iid_reg = alloc_preg (cfg);
1551                 int iid_one_bit_reg = alloc_preg (cfg);
1552                 int iid_bit_reg = alloc_preg (cfg);
1553                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1554                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1555                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1556                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1557                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1558                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1559                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1560                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1561         } else {
1562                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1563                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1564         }
1565 #endif
1566 }
1567
1568 /* 
1569  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1570  * stored in "klass_reg" implements the interface "klass".
1571  */
1572 static void
1573 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1574 {
1575         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1576 }
1577
1578 /* 
1579  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1580  * stored in "vtable_reg" implements the interface "klass".
1581  */
1582 static void
1583 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1584 {
1585         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1586 }
1587
1588 /* 
1589  * Emit code which checks whenever the interface id of @klass is smaller than
1590  * than the value given by max_iid_reg.
1591 */
1592 static void
1593 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1594                                                  MonoBasicBlock *false_target)
1595 {
1596         if (cfg->compile_aot) {
1597                 int iid_reg = alloc_preg (cfg);
1598                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1599                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1600         }
1601         else
1602                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1603         if (false_target)
1604                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1605         else
1606                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1607 }
1608
1609 /* Same as above, but obtains max_iid from a vtable */
1610 static void
1611 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1612                                                                  MonoBasicBlock *false_target)
1613 {
1614         int max_iid_reg = alloc_preg (cfg);
1615                 
1616         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1617         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1618 }
1619
1620 /* Same as above, but obtains max_iid from a klass */
1621 static void
1622 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1623                                                                  MonoBasicBlock *false_target)
1624 {
1625         int max_iid_reg = alloc_preg (cfg);
1626
1627         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1628         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1629 }
1630
1631 static void
1632 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1633 {
1634         int idepth_reg = alloc_preg (cfg);
1635         int stypes_reg = alloc_preg (cfg);
1636         int stype = alloc_preg (cfg);
1637
1638         mono_class_setup_supertypes (klass);
1639
1640         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1641                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1642                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1643                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1644         }
1645         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1646         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1647         if (klass_ins) {
1648                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1649         } else if (cfg->compile_aot) {
1650                 int const_reg = alloc_preg (cfg);
1651                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1652                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1653         } else {
1654                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1655         }
1656         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1657 }
1658
1659 static void
1660 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1661 {
1662         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1663 }
1664
1665 static void
1666 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1667 {
1668         int intf_reg = alloc_preg (cfg);
1669
1670         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1671         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1672         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1673         if (true_target)
1674                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1675         else
1676                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1677 }
1678
1679 /*
1680  * Variant of the above that takes a register to the class, not the vtable.
1681  */
1682 static void
1683 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1684 {
1685         int intf_bit_reg = alloc_preg (cfg);
1686
1687         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1688         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1689         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1690         if (true_target)
1691                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1692         else
1693                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1694 }
1695
1696 static inline void
1697 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1698 {
1699         if (klass_inst) {
1700                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1701         } else if (cfg->compile_aot) {
1702                 int const_reg = alloc_preg (cfg);
1703                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1704                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1705         } else {
1706                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1707         }
1708         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1709 }
1710
1711 static inline void
1712 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1713 {
1714         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1715 }
1716
1717 static inline void
1718 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1719 {
1720         if (cfg->compile_aot) {
1721                 int const_reg = alloc_preg (cfg);
1722                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1723                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1724         } else {
1725                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1726         }
1727         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1728 }
1729
1730 static void
1731 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1732         
1733 static void
1734 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1735 {
1736         if (klass->rank) {
1737                 int rank_reg = alloc_preg (cfg);
1738                 int eclass_reg = alloc_preg (cfg);
1739
1740                 g_assert (!klass_inst);
1741                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1742                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1743                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1744                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1745                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1746                 if (klass->cast_class == mono_defaults.object_class) {
1747                         int parent_reg = alloc_preg (cfg);
1748                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1749                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1750                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1751                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1752                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1753                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1754                 } else if (klass->cast_class == mono_defaults.enum_class) {
1755                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1756                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1757                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1758                 } else {
1759                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1760                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1761                 }
1762
1763                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1764                         /* Check that the object is a vector too */
1765                         int bounds_reg = alloc_preg (cfg);
1766                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1767                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1768                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1769                 }
1770         } else {
1771                 int idepth_reg = alloc_preg (cfg);
1772                 int stypes_reg = alloc_preg (cfg);
1773                 int stype = alloc_preg (cfg);
1774
1775                 mono_class_setup_supertypes (klass);
1776
1777                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1778                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1779                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1780                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1781                 }
1782                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1783                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1784                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1785         }
1786 }
1787
1788 static void
1789 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1790 {
1791         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1792 }
1793
1794 static void 
1795 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1796 {
1797         int val_reg;
1798
1799         g_assert (val == 0);
1800
1801         if (align == 0)
1802                 align = 4;
1803
1804         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1805                 switch (size) {
1806                 case 1:
1807                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1808                         return;
1809                 case 2:
1810                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1811                         return;
1812                 case 4:
1813                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1814                         return;
1815 #if SIZEOF_REGISTER == 8
1816                 case 8:
1817                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1818                         return;
1819 #endif
1820                 }
1821         }
1822
1823         val_reg = alloc_preg (cfg);
1824
1825         if (SIZEOF_REGISTER == 8)
1826                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1827         else
1828                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1829
1830         if (align < 4) {
1831                 /* This could be optimized further if neccesary */
1832                 while (size >= 1) {
1833                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1834                         offset += 1;
1835                         size -= 1;
1836                 }
1837                 return;
1838         }       
1839
1840 #if !NO_UNALIGNED_ACCESS
1841         if (SIZEOF_REGISTER == 8) {
1842                 if (offset % 8) {
1843                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1844                         offset += 4;
1845                         size -= 4;
1846                 }
1847                 while (size >= 8) {
1848                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1849                         offset += 8;
1850                         size -= 8;
1851                 }
1852         }       
1853 #endif
1854
1855         while (size >= 4) {
1856                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1857                 offset += 4;
1858                 size -= 4;
1859         }
1860         while (size >= 2) {
1861                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1862                 offset += 2;
1863                 size -= 2;
1864         }
1865         while (size >= 1) {
1866                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1867                 offset += 1;
1868                 size -= 1;
1869         }
1870 }
1871
1872 void 
1873 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1874 {
1875         int cur_reg;
1876
1877         if (align == 0)
1878                 align = 4;
1879
1880         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1881         g_assert (size < 10000);
1882
1883         if (align < 4) {
1884                 /* This could be optimized further if neccesary */
1885                 while (size >= 1) {
1886                         cur_reg = alloc_preg (cfg);
1887                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1888                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1889                         doffset += 1;
1890                         soffset += 1;
1891                         size -= 1;
1892                 }
1893         }
1894
1895 #if !NO_UNALIGNED_ACCESS
1896         if (SIZEOF_REGISTER == 8) {
1897                 while (size >= 8) {
1898                         cur_reg = alloc_preg (cfg);
1899                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1900                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1901                         doffset += 8;
1902                         soffset += 8;
1903                         size -= 8;
1904                 }
1905         }       
1906 #endif
1907
1908         while (size >= 4) {
1909                 cur_reg = alloc_preg (cfg);
1910                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1911                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1912                 doffset += 4;
1913                 soffset += 4;
1914                 size -= 4;
1915         }
1916         while (size >= 2) {
1917                 cur_reg = alloc_preg (cfg);
1918                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1919                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1920                 doffset += 2;
1921                 soffset += 2;
1922                 size -= 2;
1923         }
1924         while (size >= 1) {
1925                 cur_reg = alloc_preg (cfg);
1926                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1927                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1928                 doffset += 1;
1929                 soffset += 1;
1930                 size -= 1;
1931         }
1932 }
1933
1934 static void
1935 emit_tls_set (MonoCompile *cfg, int sreg1, int tls_key)
1936 {
1937         MonoInst *ins, *c;
1938
1939         if (cfg->compile_aot) {
1940                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1941                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1942                 ins->sreg1 = sreg1;
1943                 ins->sreg2 = c->dreg;
1944                 MONO_ADD_INS (cfg->cbb, ins);
1945         } else {
1946                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1947                 ins->sreg1 = sreg1;
1948                 ins->inst_offset = mini_get_tls_offset (tls_key);
1949                 MONO_ADD_INS (cfg->cbb, ins);
1950         }
1951 }
1952
1953 /*
1954  * emit_push_lmf:
1955  *
1956  *   Emit IR to push the current LMF onto the LMF stack.
1957  */
1958 static void
1959 emit_push_lmf (MonoCompile *cfg)
1960 {
1961         /*
1962          * Emit IR to push the LMF:
1963          * lmf_addr = <lmf_addr from tls>
1964          * lmf->lmf_addr = lmf_addr
1965          * lmf->prev_lmf = *lmf_addr
1966          * *lmf_addr = lmf
1967          */
1968         int lmf_reg, prev_lmf_reg;
1969         MonoInst *ins, *lmf_ins;
1970
1971         if (!cfg->lmf_ir)
1972                 return;
1973
1974         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1975                 /* Load current lmf */
1976                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1977                 g_assert (lmf_ins);
1978                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1979                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1980                 lmf_reg = ins->dreg;
1981                 /* Save previous_lmf */
1982                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
1983                 /* Set new LMF */
1984                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
1985         } else {
1986                 /*
1987                  * Store lmf_addr in a variable, so it can be allocated to a global register.
1988                  */
1989                 if (!cfg->lmf_addr_var)
1990                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1991
1992 #ifdef HOST_WIN32
1993                 ins = mono_get_jit_tls_intrinsic (cfg);
1994                 if (ins) {
1995                         int jit_tls_dreg = ins->dreg;
1996
1997                         MONO_ADD_INS (cfg->cbb, ins);
1998                         lmf_reg = alloc_preg (cfg);
1999                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2000                 } else {
2001                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2002                 }
2003 #else
2004                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2005                 if (lmf_ins) {
2006                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2007                 } else {
2008 #ifdef TARGET_IOS
2009                         MonoInst *args [16], *jit_tls_ins, *ins;
2010
2011                         /* Inline mono_get_lmf_addr () */
2012                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2013
2014                         /* Load mono_jit_tls_id */
2015                         EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2016                         /* call pthread_getspecific () */
2017                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2018                         /* lmf_addr = &jit_tls->lmf */
2019                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2020                         lmf_ins = ins;
2021 #else
2022                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2023 #endif
2024                 }
2025 #endif
2026                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2027
2028                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2029                 lmf_reg = ins->dreg;
2030
2031                 prev_lmf_reg = alloc_preg (cfg);
2032                 /* Save previous_lmf */
2033                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2034                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2035                 /* Set new lmf */
2036                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2037         }
2038 }
2039
2040 /*
2041  * emit_pop_lmf:
2042  *
2043  *   Emit IR to pop the current LMF from the LMF stack.
2044  */
2045 static void
2046 emit_pop_lmf (MonoCompile *cfg)
2047 {
2048         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2049         MonoInst *ins;
2050
2051         if (!cfg->lmf_ir)
2052                 return;
2053
2054         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2055         lmf_reg = ins->dreg;
2056
2057         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2058                 /* Load previous_lmf */
2059                 prev_lmf_reg = alloc_preg (cfg);
2060                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2061                 /* Set new LMF */
2062                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2063         } else {
2064                 /*
2065                  * Emit IR to pop the LMF:
2066                  * *(lmf->lmf_addr) = lmf->prev_lmf
2067                  */
2068                 /* This could be called before emit_push_lmf () */
2069                 if (!cfg->lmf_addr_var)
2070                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2071                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2072
2073                 prev_lmf_reg = alloc_preg (cfg);
2074                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2075                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2076         }
2077 }
2078
2079 static void
2080 emit_instrumentation_call (MonoCompile *cfg, void *func)
2081 {
2082         MonoInst *iargs [1];
2083
2084         /*
2085          * Avoid instrumenting inlined methods since it can
2086          * distort profiling results.
2087          */
2088         if (cfg->method != cfg->current_method)
2089                 return;
2090
2091         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2092                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2093                 mono_emit_jit_icall (cfg, func, iargs);
2094         }
2095 }
2096
2097 static int
2098 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
2099 {
2100         if (type->byref)
2101                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2102
2103 handle_enum:
2104         type = mini_get_basic_type_from_generic (gsctx, type);
2105         type = mini_replace_type (type);
2106         switch (type->type) {
2107         case MONO_TYPE_VOID:
2108                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2109         case MONO_TYPE_I1:
2110         case MONO_TYPE_U1:
2111         case MONO_TYPE_BOOLEAN:
2112         case MONO_TYPE_I2:
2113         case MONO_TYPE_U2:
2114         case MONO_TYPE_CHAR:
2115         case MONO_TYPE_I4:
2116         case MONO_TYPE_U4:
2117                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2118         case MONO_TYPE_I:
2119         case MONO_TYPE_U:
2120         case MONO_TYPE_PTR:
2121         case MONO_TYPE_FNPTR:
2122                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2123         case MONO_TYPE_CLASS:
2124         case MONO_TYPE_STRING:
2125         case MONO_TYPE_OBJECT:
2126         case MONO_TYPE_SZARRAY:
2127         case MONO_TYPE_ARRAY:    
2128                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2129         case MONO_TYPE_I8:
2130         case MONO_TYPE_U8:
2131                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2132         case MONO_TYPE_R4:
2133         case MONO_TYPE_R8:
2134                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2135         case MONO_TYPE_VALUETYPE:
2136                 if (type->data.klass->enumtype) {
2137                         type = mono_class_enum_basetype (type->data.klass);
2138                         goto handle_enum;
2139                 } else
2140                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2141         case MONO_TYPE_TYPEDBYREF:
2142                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2143         case MONO_TYPE_GENERICINST:
2144                 type = &type->data.generic_class->container_class->byval_arg;
2145                 goto handle_enum;
2146         case MONO_TYPE_VAR:
2147         case MONO_TYPE_MVAR:
2148                 /* gsharedvt */
2149                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2150         default:
2151                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2152         }
2153         return -1;
2154 }
2155
2156 /*
2157  * target_type_is_incompatible:
2158  * @cfg: MonoCompile context
2159  *
2160  * Check that the item @arg on the evaluation stack can be stored
2161  * in the target type (can be a local, or field, etc).
2162  * The cfg arg can be used to check if we need verification or just
2163  * validity checks.
2164  *
2165  * Returns: non-0 value if arg can't be stored on a target.
2166  */
2167 static int
2168 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2169 {
2170         MonoType *simple_type;
2171         MonoClass *klass;
2172
2173         target = mini_replace_type (target);
2174         if (target->byref) {
2175                 /* FIXME: check that the pointed to types match */
2176                 if (arg->type == STACK_MP)
2177                         return arg->klass != mono_class_from_mono_type (target);
2178                 if (arg->type == STACK_PTR)
2179                         return 0;
2180                 return 1;
2181         }
2182
2183         simple_type = mono_type_get_underlying_type (target);
2184         switch (simple_type->type) {
2185         case MONO_TYPE_VOID:
2186                 return 1;
2187         case MONO_TYPE_I1:
2188         case MONO_TYPE_U1:
2189         case MONO_TYPE_BOOLEAN:
2190         case MONO_TYPE_I2:
2191         case MONO_TYPE_U2:
2192         case MONO_TYPE_CHAR:
2193         case MONO_TYPE_I4:
2194         case MONO_TYPE_U4:
2195                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2196                         return 1;
2197                 return 0;
2198         case MONO_TYPE_PTR:
2199                 /* STACK_MP is needed when setting pinned locals */
2200                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2201                         return 1;
2202                 return 0;
2203         case MONO_TYPE_I:
2204         case MONO_TYPE_U:
2205         case MONO_TYPE_FNPTR:
2206                 /* 
2207                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2208                  * in native int. (#688008).
2209                  */
2210                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2211                         return 1;
2212                 return 0;
2213         case MONO_TYPE_CLASS:
2214         case MONO_TYPE_STRING:
2215         case MONO_TYPE_OBJECT:
2216         case MONO_TYPE_SZARRAY:
2217         case MONO_TYPE_ARRAY:    
2218                 if (arg->type != STACK_OBJ)
2219                         return 1;
2220                 /* FIXME: check type compatibility */
2221                 return 0;
2222         case MONO_TYPE_I8:
2223         case MONO_TYPE_U8:
2224                 if (arg->type != STACK_I8)
2225                         return 1;
2226                 return 0;
2227         case MONO_TYPE_R4:
2228         case MONO_TYPE_R8:
2229                 if (arg->type != STACK_R8)
2230                         return 1;
2231                 return 0;
2232         case MONO_TYPE_VALUETYPE:
2233                 if (arg->type != STACK_VTYPE)
2234                         return 1;
2235                 klass = mono_class_from_mono_type (simple_type);
2236                 if (klass != arg->klass)
2237                         return 1;
2238                 return 0;
2239         case MONO_TYPE_TYPEDBYREF:
2240                 if (arg->type != STACK_VTYPE)
2241                         return 1;
2242                 klass = mono_class_from_mono_type (simple_type);
2243                 if (klass != arg->klass)
2244                         return 1;
2245                 return 0;
2246         case MONO_TYPE_GENERICINST:
2247                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2248                         if (arg->type != STACK_VTYPE)
2249                                 return 1;
2250                         klass = mono_class_from_mono_type (simple_type);
2251                         if (klass != arg->klass)
2252                                 return 1;
2253                         return 0;
2254                 } else {
2255                         if (arg->type != STACK_OBJ)
2256                                 return 1;
2257                         /* FIXME: check type compatibility */
2258                         return 0;
2259                 }
2260         case MONO_TYPE_VAR:
2261         case MONO_TYPE_MVAR:
2262                 g_assert (cfg->generic_sharing_context);
2263                 if (mini_type_var_is_vt (cfg, simple_type)) {
2264                         if (arg->type != STACK_VTYPE)
2265                                 return 1;
2266                 } else {
2267                         if (arg->type != STACK_OBJ)
2268                                 return 1;
2269                 }
2270                 return 0;
2271         default:
2272                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2273         }
2274         return 1;
2275 }
2276
2277 /*
2278  * Prepare arguments for passing to a function call.
2279  * Return a non-zero value if the arguments can't be passed to the given
2280  * signature.
2281  * The type checks are not yet complete and some conversions may need
2282  * casts on 32 or 64 bit architectures.
2283  *
2284  * FIXME: implement this using target_type_is_incompatible ()
2285  */
2286 static int
2287 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2288 {
2289         MonoType *simple_type;
2290         int i;
2291
2292         if (sig->hasthis) {
2293                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2294                         return 1;
2295                 args++;
2296         }
2297         for (i = 0; i < sig->param_count; ++i) {
2298                 if (sig->params [i]->byref) {
2299                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2300                                 return 1;
2301                         continue;
2302                 }
2303                 simple_type = sig->params [i];
2304                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2305 handle_enum:
2306                 switch (simple_type->type) {
2307                 case MONO_TYPE_VOID:
2308                         return 1;
2309                         continue;
2310                 case MONO_TYPE_I1:
2311                 case MONO_TYPE_U1:
2312                 case MONO_TYPE_BOOLEAN:
2313                 case MONO_TYPE_I2:
2314                 case MONO_TYPE_U2:
2315                 case MONO_TYPE_CHAR:
2316                 case MONO_TYPE_I4:
2317                 case MONO_TYPE_U4:
2318                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2319                                 return 1;
2320                         continue;
2321                 case MONO_TYPE_I:
2322                 case MONO_TYPE_U:
2323                 case MONO_TYPE_PTR:
2324                 case MONO_TYPE_FNPTR:
2325                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2326                                 return 1;
2327                         continue;
2328                 case MONO_TYPE_CLASS:
2329                 case MONO_TYPE_STRING:
2330                 case MONO_TYPE_OBJECT:
2331                 case MONO_TYPE_SZARRAY:
2332                 case MONO_TYPE_ARRAY:    
2333                         if (args [i]->type != STACK_OBJ)
2334                                 return 1;
2335                         continue;
2336                 case MONO_TYPE_I8:
2337                 case MONO_TYPE_U8:
2338                         if (args [i]->type != STACK_I8)
2339                                 return 1;
2340                         continue;
2341                 case MONO_TYPE_R4:
2342                 case MONO_TYPE_R8:
2343                         if (args [i]->type != STACK_R8)
2344                                 return 1;
2345                         continue;
2346                 case MONO_TYPE_VALUETYPE:
2347                         if (simple_type->data.klass->enumtype) {
2348                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2349                                 goto handle_enum;
2350                         }
2351                         if (args [i]->type != STACK_VTYPE)
2352                                 return 1;
2353                         continue;
2354                 case MONO_TYPE_TYPEDBYREF:
2355                         if (args [i]->type != STACK_VTYPE)
2356                                 return 1;
2357                         continue;
2358                 case MONO_TYPE_GENERICINST:
2359                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2360                         goto handle_enum;
2361                 case MONO_TYPE_VAR:
2362                 case MONO_TYPE_MVAR:
2363                         /* gsharedvt */
2364                         if (args [i]->type != STACK_VTYPE)
2365                                 return 1;
2366                         continue;
2367                 default:
2368                         g_error ("unknown type 0x%02x in check_call_signature",
2369                                  simple_type->type);
2370                 }
2371         }
2372         return 0;
2373 }
2374
2375 static int
2376 callvirt_to_call (int opcode)
2377 {
2378         switch (opcode) {
2379         case OP_CALL_MEMBASE:
2380                 return OP_CALL;
2381         case OP_VOIDCALL_MEMBASE:
2382                 return OP_VOIDCALL;
2383         case OP_FCALL_MEMBASE:
2384                 return OP_FCALL;
2385         case OP_VCALL_MEMBASE:
2386                 return OP_VCALL;
2387         case OP_LCALL_MEMBASE:
2388                 return OP_LCALL;
2389         default:
2390                 g_assert_not_reached ();
2391         }
2392
2393         return -1;
2394 }
2395
2396 /* Either METHOD or IMT_ARG needs to be set */
2397 static void
2398 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2399 {
2400         int method_reg;
2401
2402         if (COMPILE_LLVM (cfg)) {
2403                 method_reg = alloc_preg (cfg);
2404
2405                 if (imt_arg) {
2406                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2407                 } else if (cfg->compile_aot) {
2408                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2409                 } else {
2410                         MonoInst *ins;
2411                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2412                         ins->inst_p0 = method;
2413                         ins->dreg = method_reg;
2414                         MONO_ADD_INS (cfg->cbb, ins);
2415                 }
2416
2417 #ifdef ENABLE_LLVM
2418                 call->imt_arg_reg = method_reg;
2419 #endif
2420 #ifdef MONO_ARCH_IMT_REG
2421         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2422 #else
2423         /* Need this to keep the IMT arg alive */
2424         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2425 #endif
2426                 return;
2427         }
2428
2429 #ifdef MONO_ARCH_IMT_REG
2430         method_reg = alloc_preg (cfg);
2431
2432         if (imt_arg) {
2433                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2434         } else if (cfg->compile_aot) {
2435                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2436         } else {
2437                 MonoInst *ins;
2438                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2439                 ins->inst_p0 = method;
2440                 ins->dreg = method_reg;
2441                 MONO_ADD_INS (cfg->cbb, ins);
2442         }
2443
2444         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2445 #else
2446         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2447 #endif
2448 }
2449
2450 static MonoJumpInfo *
2451 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2452 {
2453         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2454
2455         ji->ip.i = ip;
2456         ji->type = type;
2457         ji->data.target = target;
2458
2459         return ji;
2460 }
2461
2462 static int
2463 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2464 {
2465         if (cfg->generic_sharing_context)
2466                 return mono_class_check_context_used (klass);
2467         else
2468                 return 0;
2469 }
2470
2471 static int
2472 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2473 {
2474         if (cfg->generic_sharing_context)
2475                 return mono_method_check_context_used (method);
2476         else
2477                 return 0;
2478 }
2479
2480 /*
2481  * check_method_sharing:
2482  *
2483  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2484  */
2485 static void
2486 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2487 {
2488         gboolean pass_vtable = FALSE;
2489         gboolean pass_mrgctx = FALSE;
2490
2491         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2492                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2493                 gboolean sharable = FALSE;
2494
2495                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2496                         sharable = TRUE;
2497                 } else {
2498                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2499                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2500                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2501
2502                         sharable = sharing_enabled && context_sharable;
2503                 }
2504
2505                 /*
2506                  * Pass vtable iff target method might
2507                  * be shared, which means that sharing
2508                  * is enabled for its class and its
2509                  * context is sharable (and it's not a
2510                  * generic method).
2511                  */
2512                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2513                         pass_vtable = TRUE;
2514         }
2515
2516         if (mini_method_get_context (cmethod) &&
2517                 mini_method_get_context (cmethod)->method_inst) {
2518                 g_assert (!pass_vtable);
2519
2520                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2521                         pass_mrgctx = TRUE;
2522                 } else {
2523                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2524                         MonoGenericContext *context = mini_method_get_context (cmethod);
2525                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2526
2527                         if (sharing_enabled && context_sharable)
2528                                 pass_mrgctx = TRUE;
2529                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2530                                 pass_mrgctx = TRUE;
2531                 }
2532         }
2533
2534         if (out_pass_vtable)
2535                 *out_pass_vtable = pass_vtable;
2536         if (out_pass_mrgctx)
2537                 *out_pass_mrgctx = pass_mrgctx;
2538 }
2539
2540 inline static MonoCallInst *
2541 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2542                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2543 {
2544         MonoType *sig_ret;
2545         MonoCallInst *call;
2546 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2547         int i;
2548 #endif
2549
2550         if (tail) {
2551                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2552
2553                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2554         } else
2555                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2556
2557         call->args = args;
2558         call->signature = sig;
2559         call->rgctx_reg = rgctx;
2560         sig_ret = mini_replace_type (sig->ret);
2561
2562         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2563
2564         if (tail) {
2565                 if (mini_type_is_vtype (cfg, sig_ret)) {
2566                         call->vret_var = cfg->vret_addr;
2567                         //g_assert_not_reached ();
2568                 }
2569         } else if (mini_type_is_vtype (cfg, sig_ret)) {
2570                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2571                 MonoInst *loada;
2572
2573                 temp->backend.is_pinvoke = sig->pinvoke;
2574
2575                 /*
2576                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2577                  * address of return value to increase optimization opportunities.
2578                  * Before vtype decomposition, the dreg of the call ins itself represents the
2579                  * fact the call modifies the return value. After decomposition, the call will
2580                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2581                  * will be transformed into an LDADDR.
2582                  */
2583                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2584                 loada->dreg = alloc_preg (cfg);
2585                 loada->inst_p0 = temp;
2586                 /* We reference the call too since call->dreg could change during optimization */
2587                 loada->inst_p1 = call;
2588                 MONO_ADD_INS (cfg->cbb, loada);
2589
2590                 call->inst.dreg = temp->dreg;
2591
2592                 call->vret_var = loada;
2593         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2594                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2595
2596 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2597         if (COMPILE_SOFT_FLOAT (cfg)) {
2598                 /* 
2599                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2600                  * an icall, but that cannot be done during the call sequence since it would clobber
2601                  * the call registers + the stack. So we do it before emitting the call.
2602                  */
2603                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2604                         MonoType *t;
2605                         MonoInst *in = call->args [i];
2606
2607                         if (i >= sig->hasthis)
2608                                 t = sig->params [i - sig->hasthis];
2609                         else
2610                                 t = &mono_defaults.int_class->byval_arg;
2611                         t = mono_type_get_underlying_type (t);
2612
2613                         if (!t->byref && t->type == MONO_TYPE_R4) {
2614                                 MonoInst *iargs [1];
2615                                 MonoInst *conv;
2616
2617                                 iargs [0] = in;
2618                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2619
2620                                 /* The result will be in an int vreg */
2621                                 call->args [i] = conv;
2622                         }
2623                 }
2624         }
2625 #endif
2626
2627         call->need_unbox_trampoline = unbox_trampoline;
2628
2629 #ifdef ENABLE_LLVM
2630         if (COMPILE_LLVM (cfg))
2631                 mono_llvm_emit_call (cfg, call);
2632         else
2633                 mono_arch_emit_call (cfg, call);
2634 #else
2635         mono_arch_emit_call (cfg, call);
2636 #endif
2637
2638         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2639         cfg->flags |= MONO_CFG_HAS_CALLS;
2640         
2641         return call;
2642 }
2643
2644 static void
2645 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2646 {
2647 #ifdef MONO_ARCH_RGCTX_REG
2648         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2649         cfg->uses_rgctx_reg = TRUE;
2650         call->rgctx_reg = TRUE;
2651 #ifdef ENABLE_LLVM
2652         call->rgctx_arg_reg = rgctx_reg;
2653 #endif
2654 #else
2655         NOT_IMPLEMENTED;
2656 #endif
2657 }       
2658
2659 inline static MonoInst*
2660 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2661 {
2662         MonoCallInst *call;
2663         MonoInst *ins;
2664         int rgctx_reg = -1;
2665         gboolean check_sp = FALSE;
2666
2667         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2668                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2669
2670                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2671                         check_sp = TRUE;
2672         }
2673
2674         if (rgctx_arg) {
2675                 rgctx_reg = mono_alloc_preg (cfg);
2676                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2677         }
2678
2679         if (check_sp) {
2680                 if (!cfg->stack_inbalance_var)
2681                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2682
2683                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2684                 ins->dreg = cfg->stack_inbalance_var->dreg;
2685                 MONO_ADD_INS (cfg->cbb, ins);
2686         }
2687
2688         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2689
2690         call->inst.sreg1 = addr->dreg;
2691
2692         if (imt_arg)
2693                 emit_imt_argument (cfg, call, NULL, imt_arg);
2694
2695         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2696
2697         if (check_sp) {
2698                 int sp_reg;
2699
2700                 sp_reg = mono_alloc_preg (cfg);
2701
2702                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2703                 ins->dreg = sp_reg;
2704                 MONO_ADD_INS (cfg->cbb, ins);
2705
2706                 /* Restore the stack so we don't crash when throwing the exception */
2707                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2708                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2709                 MONO_ADD_INS (cfg->cbb, ins);
2710
2711                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2712                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2713         }
2714
2715         if (rgctx_arg)
2716                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2717
2718         return (MonoInst*)call;
2719 }
2720
2721 static MonoInst*
2722 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2723
2724 static MonoInst*
2725 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2726 static MonoInst*
2727 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2728
2729 static MonoInst*
2730 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2731                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2732 {
2733 #ifndef DISABLE_REMOTING
2734         gboolean might_be_remote = FALSE;
2735 #endif
2736         gboolean virtual = this != NULL;
2737         gboolean enable_for_aot = TRUE;
2738         int context_used;
2739         MonoCallInst *call;
2740         int rgctx_reg = 0;
2741         gboolean need_unbox_trampoline;
2742
2743         if (!sig)
2744                 sig = mono_method_signature (method);
2745
2746         if (rgctx_arg) {
2747                 rgctx_reg = mono_alloc_preg (cfg);
2748                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2749         }
2750
2751         if (method->string_ctor) {
2752                 /* Create the real signature */
2753                 /* FIXME: Cache these */
2754                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2755                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2756
2757                 sig = ctor_sig;
2758         }
2759
2760         context_used = mini_method_check_context_used (cfg, method);
2761
2762 #ifndef DISABLE_REMOTING
2763         might_be_remote = this && sig->hasthis &&
2764                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2765                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2766
2767         if (might_be_remote && context_used) {
2768                 MonoInst *addr;
2769
2770                 g_assert (cfg->generic_sharing_context);
2771
2772                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2773
2774                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2775         }
2776 #endif
2777
2778         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2779
2780         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2781
2782 #ifndef DISABLE_REMOTING
2783         if (might_be_remote)
2784                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2785         else
2786 #endif
2787                 call->method = method;
2788         call->inst.flags |= MONO_INST_HAS_METHOD;
2789         call->inst.inst_left = this;
2790         call->tail_call = tail;
2791
2792         if (virtual) {
2793                 int vtable_reg, slot_reg, this_reg;
2794                 int offset;
2795
2796                 this_reg = this->dreg;
2797
2798                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2799                         MonoInst *dummy_use;
2800
2801                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2802
2803                         /* Make a call to delegate->invoke_impl */
2804                         call->inst.inst_basereg = this_reg;
2805                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2806                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2807
2808                         /* We must emit a dummy use here because the delegate trampoline will
2809                         replace the 'this' argument with the delegate target making this activation
2810                         no longer a root for the delegate.
2811                         This is an issue for delegates that target collectible code such as dynamic
2812                         methods of GC'able assemblies.
2813
2814                         For a test case look into #667921.
2815
2816                         FIXME: a dummy use is not the best way to do it as the local register allocator
2817                         will put it on a caller save register and spil it around the call. 
2818                         Ideally, we would either put it on a callee save register or only do the store part.  
2819                          */
2820                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2821
2822                         return (MonoInst*)call;
2823                 }
2824
2825                 if ((!cfg->compile_aot || enable_for_aot) && 
2826                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2827                          (MONO_METHOD_IS_FINAL (method) &&
2828                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2829                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2830                         /* 
2831                          * the method is not virtual, we just need to ensure this is not null
2832                          * and then we can call the method directly.
2833                          */
2834 #ifndef DISABLE_REMOTING
2835                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2836                                 /* 
2837                                  * The check above ensures method is not gshared, this is needed since
2838                                  * gshared methods can't have wrappers.
2839                                  */
2840                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2841                         }
2842 #endif
2843
2844                         if (!method->string_ctor)
2845                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2846
2847                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2848                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2849                         /*
2850                          * the method is virtual, but we can statically dispatch since either
2851                          * it's class or the method itself are sealed.
2852                          * But first we need to ensure it's not a null reference.
2853                          */
2854                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2855
2856                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2857                 } else {
2858                         vtable_reg = alloc_preg (cfg);
2859                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2860                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2861                                 slot_reg = -1;
2862                                 if (mono_use_imt) {
2863                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2864                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2865                                         slot_reg = vtable_reg;
2866                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2867                                 }
2868                                 if (slot_reg == -1) {
2869                                         slot_reg = alloc_preg (cfg);
2870                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2871                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2872                                 }
2873                         } else {
2874                                 slot_reg = vtable_reg;
2875                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2876                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2877                                 if (imt_arg) {
2878                                         g_assert (mono_method_signature (method)->generic_param_count);
2879                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2880                                 }
2881                         }
2882
2883                         call->inst.sreg1 = slot_reg;
2884                         call->inst.inst_offset = offset;
2885                         call->virtual = TRUE;
2886                 }
2887         }
2888
2889         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2890
2891         if (rgctx_arg)
2892                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2893
2894         return (MonoInst*)call;
2895 }
2896
2897 MonoInst*
2898 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2899 {
2900         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2901 }
2902
2903 MonoInst*
2904 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2905                                            MonoInst **args)
2906 {
2907         MonoCallInst *call;
2908
2909         g_assert (sig);
2910
2911         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2912         call->fptr = func;
2913
2914         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2915
2916         return (MonoInst*)call;
2917 }
2918
2919 MonoInst*
2920 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2921 {
2922         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2923
2924         g_assert (info);
2925
2926         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2927 }
2928
2929 /*
2930  * mono_emit_abs_call:
2931  *
2932  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2933  */
2934 inline static MonoInst*
2935 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2936                                         MonoMethodSignature *sig, MonoInst **args)
2937 {
2938         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2939         MonoInst *ins;
2940
2941         /* 
2942          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2943          * handle it.
2944          */
2945         if (cfg->abs_patches == NULL)
2946                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2947         g_hash_table_insert (cfg->abs_patches, ji, ji);
2948         ins = mono_emit_native_call (cfg, ji, sig, args);
2949         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2950         return ins;
2951 }
2952  
2953 static MonoInst*
2954 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2955 {
2956         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2957                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2958                         int widen_op = -1;
2959
2960                         /* 
2961                          * Native code might return non register sized integers 
2962                          * without initializing the upper bits.
2963                          */
2964                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2965                         case OP_LOADI1_MEMBASE:
2966                                 widen_op = OP_ICONV_TO_I1;
2967                                 break;
2968                         case OP_LOADU1_MEMBASE:
2969                                 widen_op = OP_ICONV_TO_U1;
2970                                 break;
2971                         case OP_LOADI2_MEMBASE:
2972                                 widen_op = OP_ICONV_TO_I2;
2973                                 break;
2974                         case OP_LOADU2_MEMBASE:
2975                                 widen_op = OP_ICONV_TO_U2;
2976                                 break;
2977                         default:
2978                                 break;
2979                         }
2980
2981                         if (widen_op != -1) {
2982                                 int dreg = alloc_preg (cfg);
2983                                 MonoInst *widen;
2984
2985                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2986                                 widen->type = ins->type;
2987                                 ins = widen;
2988                         }
2989                 }
2990         }
2991
2992         return ins;
2993 }
2994
2995 static MonoMethod*
2996 get_memcpy_method (void)
2997 {
2998         static MonoMethod *memcpy_method = NULL;
2999         if (!memcpy_method) {
3000                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3001                 if (!memcpy_method)
3002                         g_error ("Old corlib found. Install a new one");
3003         }
3004         return memcpy_method;
3005 }
3006
3007 static void
3008 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3009 {
3010         MonoClassField *field;
3011         gpointer iter = NULL;
3012
3013         while ((field = mono_class_get_fields (klass, &iter))) {
3014                 int foffset;
3015
3016                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3017                         continue;
3018                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3019                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
3020                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3021                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3022                 } else {
3023                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3024                         if (field_class->has_references)
3025                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3026                 }
3027         }
3028 }
3029
3030 static void
3031 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3032 {
3033         int card_table_shift_bits;
3034         gpointer card_table_mask;
3035         guint8 *card_table;
3036         MonoInst *dummy_use;
3037         int nursery_shift_bits;
3038         size_t nursery_size;
3039         gboolean has_card_table_wb = FALSE;
3040
3041         if (!cfg->gen_write_barriers)
3042                 return;
3043
3044         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3045
3046         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3047
3048 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
3049         has_card_table_wb = TRUE;
3050 #endif
3051
3052         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3053                 MonoInst *wbarrier;
3054
3055                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3056                 wbarrier->sreg1 = ptr->dreg;
3057                 wbarrier->sreg2 = value->dreg;
3058                 MONO_ADD_INS (cfg->cbb, wbarrier);
3059         } else if (card_table) {
3060                 int offset_reg = alloc_preg (cfg);
3061                 int card_reg  = alloc_preg (cfg);
3062                 MonoInst *ins;
3063
3064                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3065                 if (card_table_mask)
3066                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3067
3068                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3069                  * IMM's larger than 32bits.
3070                  */
3071                 if (cfg->compile_aot) {
3072                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
3073                 } else {
3074                         MONO_INST_NEW (cfg, ins, OP_PCONST);
3075                         ins->inst_p0 = card_table;
3076                         ins->dreg = card_reg;
3077                         MONO_ADD_INS (cfg->cbb, ins);
3078                 }
3079
3080                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3081                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3082         } else {
3083                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3084                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3085         }
3086
3087         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3088 }
3089
3090 static gboolean
3091 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3092 {
3093         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3094         unsigned need_wb = 0;
3095
3096         if (align == 0)
3097                 align = 4;
3098
3099         /*types with references can't have alignment smaller than sizeof(void*) */
3100         if (align < SIZEOF_VOID_P)
3101                 return FALSE;
3102
3103         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3104         if (size > 32 * SIZEOF_VOID_P)
3105                 return FALSE;
3106
3107         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3108
3109         /* We don't unroll more than 5 stores to avoid code bloat. */
3110         if (size > 5 * SIZEOF_VOID_P) {
3111                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3112                 size += (SIZEOF_VOID_P - 1);
3113                 size &= ~(SIZEOF_VOID_P - 1);
3114
3115                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3116                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3117                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3118                 return TRUE;
3119         }
3120
3121         destreg = iargs [0]->dreg;
3122         srcreg = iargs [1]->dreg;
3123         offset = 0;
3124
3125         dest_ptr_reg = alloc_preg (cfg);
3126         tmp_reg = alloc_preg (cfg);
3127
3128         /*tmp = dreg*/
3129         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3130
3131         while (size >= SIZEOF_VOID_P) {
3132                 MonoInst *load_inst;
3133                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3134                 load_inst->dreg = tmp_reg;
3135                 load_inst->inst_basereg = srcreg;
3136                 load_inst->inst_offset = offset;
3137                 MONO_ADD_INS (cfg->cbb, load_inst);
3138
3139                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3140
3141                 if (need_wb & 0x1)
3142                         emit_write_barrier (cfg, iargs [0], load_inst);
3143
3144                 offset += SIZEOF_VOID_P;
3145                 size -= SIZEOF_VOID_P;
3146                 need_wb >>= 1;
3147
3148                 /*tmp += sizeof (void*)*/
3149                 if (size >= SIZEOF_VOID_P) {
3150                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3151                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3152                 }
3153         }
3154
3155         /* Those cannot be references since size < sizeof (void*) */
3156         while (size >= 4) {
3157                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3158                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3159                 offset += 4;
3160                 size -= 4;
3161         }
3162
3163         while (size >= 2) {
3164                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3165                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3166                 offset += 2;
3167                 size -= 2;
3168         }
3169
3170         while (size >= 1) {
3171                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3172                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3173                 offset += 1;
3174                 size -= 1;
3175         }
3176
3177         return TRUE;
3178 }
3179
3180 /*
3181  * Emit code to copy a valuetype of type @klass whose address is stored in
3182  * @src->dreg to memory whose address is stored at @dest->dreg.
3183  */
3184 void
3185 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3186 {
3187         MonoInst *iargs [4];
3188         int context_used, n;
3189         guint32 align = 0;
3190         MonoMethod *memcpy_method;
3191         MonoInst *size_ins = NULL;
3192         MonoInst *memcpy_ins = NULL;
3193
3194         g_assert (klass);
3195         /*
3196          * This check breaks with spilled vars... need to handle it during verification anyway.
3197          * g_assert (klass && klass == src->klass && klass == dest->klass);
3198          */
3199
3200         if (mini_is_gsharedvt_klass (cfg, klass)) {
3201                 g_assert (!native);
3202                 context_used = mini_class_check_context_used (cfg, klass);
3203                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3204                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3205         }
3206
3207         if (native)
3208                 n = mono_class_native_size (klass, &align);
3209         else
3210                 n = mono_class_value_size (klass, &align);
3211
3212         /* if native is true there should be no references in the struct */
3213         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3214                 /* Avoid barriers when storing to the stack */
3215                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3216                           (dest->opcode == OP_LDADDR))) {
3217                         int context_used;
3218
3219                         iargs [0] = dest;
3220                         iargs [1] = src;
3221
3222                         context_used = mini_class_check_context_used (cfg, klass);
3223
3224                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3225                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3226                                 return;
3227                         } else if (context_used) {
3228                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3229                         }  else {
3230                                 if (cfg->compile_aot) {
3231                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
3232                                 } else {
3233                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
3234                                         mono_class_compute_gc_descriptor (klass);
3235                                 }
3236                         }
3237
3238                         if (size_ins)
3239                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3240                         else
3241                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3242                         return;
3243                 }
3244         }
3245
3246         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3247                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3248                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3249         } else {
3250                 iargs [0] = dest;
3251                 iargs [1] = src;
3252                 if (size_ins)
3253                         iargs [2] = size_ins;
3254                 else
3255                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3256                 
3257                 memcpy_method = get_memcpy_method ();
3258                 if (memcpy_ins)
3259                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3260                 else
3261                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3262         }
3263 }
3264
3265 static MonoMethod*
3266 get_memset_method (void)
3267 {
3268         static MonoMethod *memset_method = NULL;
3269         if (!memset_method) {
3270                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3271                 if (!memset_method)
3272                         g_error ("Old corlib found. Install a new one");
3273         }
3274         return memset_method;
3275 }
3276
3277 void
3278 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3279 {
3280         MonoInst *iargs [3];
3281         int n, context_used;
3282         guint32 align;
3283         MonoMethod *memset_method;
3284         MonoInst *size_ins = NULL;
3285         MonoInst *bzero_ins = NULL;
3286         static MonoMethod *bzero_method;
3287
3288         /* FIXME: Optimize this for the case when dest is an LDADDR */
3289
3290         mono_class_init (klass);
3291         if (mini_is_gsharedvt_klass (cfg, klass)) {
3292                 context_used = mini_class_check_context_used (cfg, klass);
3293                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3294                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3295                 if (!bzero_method)
3296                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3297                 g_assert (bzero_method);
3298                 iargs [0] = dest;
3299                 iargs [1] = size_ins;
3300                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3301                 return;
3302         }
3303
3304         n = mono_class_value_size (klass, &align);
3305
3306         if (n <= sizeof (gpointer) * 5) {
3307                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3308         }
3309         else {
3310                 memset_method = get_memset_method ();
3311                 iargs [0] = dest;
3312                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3313                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3314                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3315         }
3316 }
3317
3318 static MonoInst*
3319 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3320 {
3321         MonoInst *this = NULL;
3322
3323         g_assert (cfg->generic_sharing_context);
3324
3325         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3326                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3327                         !method->klass->valuetype)
3328                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3329
3330         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3331                 MonoInst *mrgctx_loc, *mrgctx_var;
3332
3333                 g_assert (!this);
3334                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3335
3336                 mrgctx_loc = mono_get_vtable_var (cfg);
3337                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3338
3339                 return mrgctx_var;
3340         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3341                 MonoInst *vtable_loc, *vtable_var;
3342
3343                 g_assert (!this);
3344
3345                 vtable_loc = mono_get_vtable_var (cfg);
3346                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3347
3348                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3349                         MonoInst *mrgctx_var = vtable_var;
3350                         int vtable_reg;
3351
3352                         vtable_reg = alloc_preg (cfg);
3353                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3354                         vtable_var->type = STACK_PTR;
3355                 }
3356
3357                 return vtable_var;
3358         } else {
3359                 MonoInst *ins;
3360                 int vtable_reg;
3361         
3362                 vtable_reg = alloc_preg (cfg);
3363                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3364                 return ins;
3365         }
3366 }
3367
3368 static MonoJumpInfoRgctxEntry *
3369 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3370 {
3371         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3372         res->method = method;
3373         res->in_mrgctx = in_mrgctx;
3374         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3375         res->data->type = patch_type;
3376         res->data->data.target = patch_data;
3377         res->info_type = info_type;
3378
3379         return res;
3380 }
3381
3382 static inline MonoInst*
3383 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3384 {
3385         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3386 }
3387
3388 static MonoInst*
3389 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3390                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3391 {
3392         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);
3393         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3394
3395         return emit_rgctx_fetch (cfg, rgctx, entry);
3396 }
3397
3398 static MonoInst*
3399 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3400                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3401 {
3402         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);
3403         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3404
3405         return emit_rgctx_fetch (cfg, rgctx, entry);
3406 }
3407
3408 static MonoInst*
3409 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3410                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3411 {
3412         MonoJumpInfoGSharedVtCall *call_info;
3413         MonoJumpInfoRgctxEntry *entry;
3414         MonoInst *rgctx;
3415
3416         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3417         call_info->sig = sig;
3418         call_info->method = cmethod;
3419
3420         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);
3421         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3422
3423         return emit_rgctx_fetch (cfg, rgctx, entry);
3424 }
3425
3426
3427 static MonoInst*
3428 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3429                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3430 {
3431         MonoJumpInfoRgctxEntry *entry;
3432         MonoInst *rgctx;
3433
3434         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);
3435         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3436
3437         return emit_rgctx_fetch (cfg, rgctx, entry);
3438 }
3439
3440 /*
3441  * emit_get_rgctx_method:
3442  *
3443  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3444  * normal constants, else emit a load from the rgctx.
3445  */
3446 static MonoInst*
3447 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3448                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3449 {
3450         if (!context_used) {
3451                 MonoInst *ins;
3452
3453                 switch (rgctx_type) {
3454                 case MONO_RGCTX_INFO_METHOD:
3455                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3456                         return ins;
3457                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3458                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3459                         return ins;
3460                 default:
3461                         g_assert_not_reached ();
3462                 }
3463         } else {
3464                 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);
3465                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3466
3467                 return emit_rgctx_fetch (cfg, rgctx, entry);
3468         }
3469 }
3470
3471 static MonoInst*
3472 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3473                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3474 {
3475         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);
3476         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3477
3478         return emit_rgctx_fetch (cfg, rgctx, entry);
3479 }
3480
3481 static int
3482 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3483 {
3484         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3485         MonoRuntimeGenericContextInfoTemplate *template;
3486         int i, idx;
3487
3488         g_assert (info);
3489
3490         for (i = 0; i < info->num_entries; ++i) {
3491                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3492
3493                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3494                         return i;
3495         }
3496
3497         if (info->num_entries == info->count_entries) {
3498                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3499                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3500
3501                 new_entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3502
3503                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3504                 info->entries = new_entries;
3505                 info->count_entries = new_count_entries;
3506         }
3507
3508         idx = info->num_entries;
3509         template = &info->entries [idx];
3510         template->info_type = rgctx_type;
3511         template->data = data;
3512
3513         info->num_entries ++;
3514
3515         return idx;
3516 }
3517
3518 /*
3519  * emit_get_gsharedvt_info:
3520  *
3521  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3522  */
3523 static MonoInst*
3524 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3525 {
3526         MonoInst *ins;
3527         int idx, dreg;
3528
3529         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3530         /* Load info->entries [idx] */
3531         dreg = alloc_preg (cfg);
3532         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3533
3534         return ins;
3535 }
3536
3537 static MonoInst*
3538 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3539 {
3540         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3541 }
3542
3543 /*
3544  * On return the caller must check @klass for load errors.
3545  */
3546 static void
3547 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3548 {
3549         MonoInst *vtable_arg;
3550         MonoCallInst *call;
3551         int context_used;
3552
3553         context_used = mini_class_check_context_used (cfg, klass);
3554
3555         if (context_used) {
3556                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3557                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3558         } else {
3559                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3560
3561                 if (!vtable)
3562                         return;
3563                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3564         }
3565
3566         if (COMPILE_LLVM (cfg))
3567                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3568         else
3569                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3570 #ifdef MONO_ARCH_VTABLE_REG
3571         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3572         cfg->uses_vtable_reg = TRUE;
3573 #else
3574         NOT_IMPLEMENTED;
3575 #endif
3576 }
3577
3578 static void
3579 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3580 {
3581         MonoInst *ins;
3582
3583         if (cfg->gen_seq_points && cfg->method == method) {
3584                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3585                 if (nonempty_stack)
3586                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3587                 MONO_ADD_INS (cfg->cbb, ins);
3588         }
3589 }
3590
3591 static void
3592 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3593 {
3594         if (mini_get_debug_options ()->better_cast_details) {
3595                 int vtable_reg = alloc_preg (cfg);
3596                 int klass_reg = alloc_preg (cfg);
3597                 MonoBasicBlock *is_null_bb = NULL;
3598                 MonoInst *tls_get;
3599                 int to_klass_reg, context_used;
3600
3601                 if (null_check) {
3602                         NEW_BBLOCK (cfg, is_null_bb);
3603
3604                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3605                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3606                 }
3607
3608                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3609                 if (!tls_get) {
3610                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3611                         exit (1);
3612                 }
3613
3614                 MONO_ADD_INS (cfg->cbb, tls_get);
3615                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3616                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3617
3618                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3619
3620                 context_used = mini_class_check_context_used (cfg, klass);
3621                 if (context_used) {
3622                         MonoInst *class_ins;
3623
3624                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3625                         to_klass_reg = class_ins->dreg;
3626                 } else {
3627                         to_klass_reg = alloc_preg (cfg);
3628                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3629                 }
3630                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3631
3632                 if (null_check) {
3633                         MONO_START_BB (cfg, is_null_bb);
3634                         if (out_bblock)
3635                                 *out_bblock = cfg->cbb;
3636                 }
3637         }
3638 }
3639
3640 static void
3641 reset_cast_details (MonoCompile *cfg)
3642 {
3643         /* Reset the variables holding the cast details */
3644         if (mini_get_debug_options ()->better_cast_details) {
3645                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3646
3647                 MONO_ADD_INS (cfg->cbb, tls_get);
3648                 /* It is enough to reset the from field */
3649                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3650         }
3651 }
3652
3653 /*
3654  * On return the caller must check @array_class for load errors
3655  */
3656 static void
3657 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3658 {
3659         int vtable_reg = alloc_preg (cfg);
3660         int context_used;
3661
3662         context_used = mini_class_check_context_used (cfg, array_class);
3663
3664         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3665
3666         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3667
3668         if (cfg->opt & MONO_OPT_SHARED) {
3669                 int class_reg = alloc_preg (cfg);
3670                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3671                 if (cfg->compile_aot) {
3672                         int klass_reg = alloc_preg (cfg);
3673                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3674                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3675                 } else {
3676                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3677                 }
3678         } else if (context_used) {
3679                 MonoInst *vtable_ins;
3680
3681                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3682                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3683         } else {
3684                 if (cfg->compile_aot) {
3685                         int vt_reg;
3686                         MonoVTable *vtable;
3687
3688                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3689                                 return;
3690                         vt_reg = alloc_preg (cfg);
3691                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3692                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3693                 } else {
3694                         MonoVTable *vtable;
3695                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3696                                 return;
3697                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3698                 }
3699         }
3700         
3701         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3702
3703         reset_cast_details (cfg);
3704 }
3705
3706 /**
3707  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3708  * generic code is generated.
3709  */
3710 static MonoInst*
3711 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3712 {
3713         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3714
3715         if (context_used) {
3716                 MonoInst *rgctx, *addr;
3717
3718                 /* FIXME: What if the class is shared?  We might not
3719                    have to get the address of the method from the
3720                    RGCTX. */
3721                 addr = emit_get_rgctx_method (cfg, context_used, method,
3722                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3723
3724                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3725
3726                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3727         } else {
3728                 gboolean pass_vtable, pass_mrgctx;
3729                 MonoInst *rgctx_arg = NULL;
3730
3731                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3732                 g_assert (!pass_mrgctx);
3733
3734                 if (pass_vtable) {
3735                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3736
3737                         g_assert (vtable);
3738                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3739                 }
3740
3741                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3742         }
3743 }
3744
3745 static MonoInst*
3746 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3747 {
3748         MonoInst *add;
3749         int obj_reg;
3750         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3751         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3752         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3753         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3754
3755         obj_reg = sp [0]->dreg;
3756         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3757         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
3758
3759         /* FIXME: generics */
3760         g_assert (klass->rank == 0);
3761                         
3762         // Check rank == 0
3763         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3764         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3765
3766         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3767         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
3768
3769         if (context_used) {
3770                 MonoInst *element_class;
3771
3772                 /* This assertion is from the unboxcast insn */
3773                 g_assert (klass->rank == 0);
3774
3775                 element_class = emit_get_rgctx_klass (cfg, context_used,
3776                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3777
3778                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3779                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3780         } else {
3781                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3782                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3783                 reset_cast_details (cfg);
3784         }
3785
3786         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3787         MONO_ADD_INS (cfg->cbb, add);
3788         add->type = STACK_MP;
3789         add->klass = klass;
3790
3791         return add;
3792 }
3793
3794 static MonoInst*
3795 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3796 {
3797         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3798         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3799         MonoInst *ins;
3800         int dreg, addr_reg;
3801
3802         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3803
3804         /* obj */
3805         args [0] = obj;
3806
3807         /* klass */
3808         args [1] = klass_inst;
3809
3810         /* CASTCLASS */
3811         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3812
3813         NEW_BBLOCK (cfg, is_ref_bb);
3814         NEW_BBLOCK (cfg, is_nullable_bb);
3815         NEW_BBLOCK (cfg, end_bb);
3816         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3817         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3818         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3819
3820         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3821         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3822
3823         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3824         addr_reg = alloc_dreg (cfg, STACK_MP);
3825
3826         /* Non-ref case */
3827         /* UNBOX */
3828         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3829         MONO_ADD_INS (cfg->cbb, addr);
3830
3831         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3832
3833         /* Ref case */
3834         MONO_START_BB (cfg, is_ref_bb);
3835
3836         /* Save the ref to a temporary */
3837         dreg = alloc_ireg (cfg);
3838         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3839         addr->dreg = addr_reg;
3840         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3841         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3842
3843         /* Nullable case */
3844         MONO_START_BB (cfg, is_nullable_bb);
3845
3846         {
3847                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3848                 MonoInst *unbox_call;
3849                 MonoMethodSignature *unbox_sig;
3850                 MonoInst *var;
3851
3852                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3853
3854                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3855                 unbox_sig->ret = &klass->byval_arg;
3856                 unbox_sig->param_count = 1;
3857                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3858                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3859
3860                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3861                 addr->dreg = addr_reg;
3862         }
3863
3864         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3865
3866         /* End */
3867         MONO_START_BB (cfg, end_bb);
3868
3869         /* LDOBJ */
3870         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3871
3872         *out_cbb = cfg->cbb;
3873
3874         return ins;
3875 }
3876
3877 /*
3878  * Returns NULL and set the cfg exception on error.
3879  */
3880 static MonoInst*
3881 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3882 {
3883         MonoInst *iargs [2];
3884         void *alloc_ftn;
3885
3886         if (context_used) {
3887                 MonoInst *data;
3888                 int rgctx_info;
3889                 MonoInst *iargs [2];
3890                 gboolean known_instance_size = !mini_is_gsharedvt_klass (cfg, klass);
3891
3892                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
3893
3894                 if (cfg->opt & MONO_OPT_SHARED)
3895                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3896                 else
3897                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3898                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3899
3900                 if (cfg->opt & MONO_OPT_SHARED) {
3901                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3902                         iargs [1] = data;
3903                         alloc_ftn = mono_object_new;
3904                 } else {
3905                         iargs [0] = data;
3906                         alloc_ftn = mono_object_new_specific;
3907                 }
3908
3909                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
3910                         if (known_instance_size)
3911                                 EMIT_NEW_ICONST (cfg, iargs [1], klass->instance_size);
3912                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3913                 }
3914
3915                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3916         }
3917
3918         if (cfg->opt & MONO_OPT_SHARED) {
3919                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3920                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3921
3922                 alloc_ftn = mono_object_new;
3923         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3924                 /* This happens often in argument checking code, eg. throw new FooException... */
3925                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3926                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3927                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3928         } else {
3929                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3930                 MonoMethod *managed_alloc = NULL;
3931                 gboolean pass_lw;
3932
3933                 if (!vtable) {
3934                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3935                         cfg->exception_ptr = klass;
3936                         return NULL;
3937                 }
3938
3939 #ifndef MONO_CROSS_COMPILE
3940                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
3941 #endif
3942
3943                 if (managed_alloc) {
3944                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3945                         EMIT_NEW_ICONST (cfg, iargs [1], klass->instance_size);
3946                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3947                 }
3948                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3949                 if (pass_lw) {
3950                         guint32 lw = vtable->klass->instance_size;
3951                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3952                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3953                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3954                 }
3955                 else {
3956                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3957                 }
3958         }
3959
3960         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3961 }
3962         
3963 /*
3964  * Returns NULL and set the cfg exception on error.
3965  */     
3966 static MonoInst*
3967 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3968 {
3969         MonoInst *alloc, *ins;
3970
3971         *out_cbb = cfg->cbb;
3972
3973         if (mono_class_is_nullable (klass)) {
3974                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3975
3976                 if (context_used) {
3977                         /* FIXME: What if the class is shared?  We might not
3978                            have to get the method address from the RGCTX. */
3979                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3980                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3981                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3982
3983                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3984                 } else {
3985                         gboolean pass_vtable, pass_mrgctx;
3986                         MonoInst *rgctx_arg = NULL;
3987
3988                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3989                         g_assert (!pass_mrgctx);
3990
3991                         if (pass_vtable) {
3992                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3993
3994                                 g_assert (vtable);
3995                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3996                         }
3997
3998                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3999                 }
4000         }
4001
4002         if (mini_is_gsharedvt_klass (cfg, klass)) {
4003                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4004                 MonoInst *res, *is_ref, *src_var, *addr;
4005                 int addr_reg, dreg;
4006
4007                 dreg = alloc_ireg (cfg);
4008
4009                 NEW_BBLOCK (cfg, is_ref_bb);
4010                 NEW_BBLOCK (cfg, is_nullable_bb);
4011                 NEW_BBLOCK (cfg, end_bb);
4012                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4013                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4014                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4015
4016                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4017                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4018
4019                 /* Non-ref case */
4020                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4021                 if (!alloc)
4022                         return NULL;
4023                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4024                 ins->opcode = OP_STOREV_MEMBASE;
4025
4026                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4027                 res->type = STACK_OBJ;
4028                 res->klass = klass;
4029                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4030                 
4031                 /* Ref case */
4032                 MONO_START_BB (cfg, is_ref_bb);
4033                 addr_reg = alloc_ireg (cfg);
4034
4035                 /* val is a vtype, so has to load the value manually */
4036                 src_var = get_vreg_to_inst (cfg, val->dreg);
4037                 if (!src_var)
4038                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4039                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4040                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4041                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4042
4043                 /* Nullable case */
4044                 MONO_START_BB (cfg, is_nullable_bb);
4045
4046                 {
4047                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4048                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4049                         MonoInst *box_call;
4050                         MonoMethodSignature *box_sig;
4051
4052                         /*
4053                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4054                          * construct that method at JIT time, so have to do things by hand.
4055                          */
4056                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4057                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4058                         box_sig->param_count = 1;
4059                         box_sig->params [0] = &klass->byval_arg;
4060                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4061                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4062                         res->type = STACK_OBJ;
4063                         res->klass = klass;
4064                 }
4065
4066                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4067
4068                 MONO_START_BB (cfg, end_bb);
4069
4070                 *out_cbb = cfg->cbb;
4071
4072                 return res;
4073         } else {
4074                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4075                 if (!alloc)
4076                         return NULL;
4077
4078                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4079                 return alloc;
4080         }
4081 }
4082
4083
4084 static gboolean
4085 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4086 {
4087         int i;
4088         MonoGenericContainer *container;
4089         MonoGenericInst *ginst;
4090
4091         if (klass->generic_class) {
4092                 container = klass->generic_class->container_class->generic_container;
4093                 ginst = klass->generic_class->context.class_inst;
4094         } else if (klass->generic_container && context_used) {
4095                 container = klass->generic_container;
4096                 ginst = container->context.class_inst;
4097         } else {
4098                 return FALSE;
4099         }
4100
4101         for (i = 0; i < container->type_argc; ++i) {
4102                 MonoType *type;
4103                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4104                         continue;
4105                 type = ginst->type_argv [i];
4106                 if (mini_type_is_reference (cfg, type))
4107                         return TRUE;
4108         }
4109         return FALSE;
4110 }
4111
4112 #define is_complex_isinst(klass) ((klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
4113
4114 static MonoInst*
4115 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4116 {
4117         MonoMethod *mono_castclass;
4118         MonoInst *res;
4119
4120         mono_castclass = mono_marshal_get_castclass_with_cache ();
4121
4122         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4123         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4124         reset_cast_details (cfg);
4125         *out_bblock = cfg->cbb;
4126
4127         return res;
4128 }
4129
4130 static MonoInst*
4131 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock)
4132 {
4133         MonoInst *args [3];
4134         int idx;
4135
4136         /* obj */
4137         args [0] = obj;
4138
4139         /* klass */
4140         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4141
4142         /* inline cache*/
4143         if (cfg->compile_aot) {
4144                 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4145                 cfg->castclass_cache_index ++;
4146                 idx = (cfg->method_index << 16) | cfg->castclass_cache_index;
4147                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4148         } else {
4149                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4150         }
4151
4152         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4153
4154         return emit_castclass_with_cache (cfg, klass, args, out_bblock);
4155 }
4156
4157 /*
4158  * Returns NULL and set the cfg exception on error.
4159  */
4160 static MonoInst*
4161 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, MonoBasicBlock **out_bb, int *inline_costs)
4162 {
4163         MonoBasicBlock *is_null_bb;
4164         int obj_reg = src->dreg;
4165         int vtable_reg = alloc_preg (cfg);
4166         int context_used;
4167         MonoInst *klass_inst = NULL, *res;
4168         MonoBasicBlock *bblock;
4169
4170         *out_bb = cfg->cbb;
4171
4172         context_used = mini_class_check_context_used (cfg, klass);
4173
4174         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4175                 res = emit_castclass_with_cache_nonshared (cfg, src, klass, &bblock);
4176                 (*inline_costs) += 2;
4177                 *out_bb = cfg->cbb;
4178                 return res;
4179         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4180                 MonoMethod *mono_castclass;
4181                 MonoInst *iargs [1];
4182                 int costs;
4183
4184                 mono_castclass = mono_marshal_get_castclass (klass); 
4185                 iargs [0] = src;
4186                                 
4187                 save_cast_details (cfg, klass, src->dreg, TRUE, &bblock);
4188                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4189                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
4190                 reset_cast_details (cfg);
4191                 CHECK_CFG_EXCEPTION;
4192                 g_assert (costs > 0);
4193                                 
4194                 cfg->real_offset += 5;
4195
4196                 (*inline_costs) += costs;
4197
4198                 *out_bb = cfg->cbb;
4199                 return src;
4200         }
4201
4202         if (context_used) {
4203                 MonoInst *args [3];
4204
4205                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4206                         MonoInst *cache_ins;
4207
4208                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4209
4210                         /* obj */
4211                         args [0] = src;
4212
4213                         /* klass - it's the second element of the cache entry*/
4214                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4215
4216                         /* cache */
4217                         args [2] = cache_ins;
4218
4219                         return emit_castclass_with_cache (cfg, klass, args, out_bb);
4220                 }
4221
4222                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4223         }
4224
4225         NEW_BBLOCK (cfg, is_null_bb);
4226
4227         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4228         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4229
4230         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4231
4232         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4233                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4234                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4235         } else {
4236                 int klass_reg = alloc_preg (cfg);
4237
4238                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4239
4240                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4241                         /* the remoting code is broken, access the class for now */
4242                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4243                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4244                                 if (!vt) {
4245                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4246                                         cfg->exception_ptr = klass;
4247                                         return NULL;
4248                                 }
4249                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4250                         } else {
4251                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4252                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4253                         }
4254                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4255                 } else {
4256                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4257                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4258                 }
4259         }
4260
4261         MONO_START_BB (cfg, is_null_bb);
4262
4263         reset_cast_details (cfg);
4264
4265         *out_bb = cfg->cbb;
4266
4267         return src;
4268
4269 exception_exit:
4270         return NULL;
4271 }
4272
4273 /*
4274  * Returns NULL and set the cfg exception on error.
4275  */
4276 static MonoInst*
4277 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4278 {
4279         MonoInst *ins;
4280         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4281         int obj_reg = src->dreg;
4282         int vtable_reg = alloc_preg (cfg);
4283         int res_reg = alloc_ireg_ref (cfg);
4284         MonoInst *klass_inst = NULL;
4285
4286         if (context_used) {
4287                 MonoInst *args [3];
4288
4289                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4290                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4291                         MonoInst *cache_ins;
4292
4293                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4294
4295                         /* obj */
4296                         args [0] = src;
4297
4298                         /* klass - it's the second element of the cache entry*/
4299                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4300
4301                         /* cache */
4302                         args [2] = cache_ins;
4303
4304                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4305                 }
4306
4307                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4308         }
4309
4310         NEW_BBLOCK (cfg, is_null_bb);
4311         NEW_BBLOCK (cfg, false_bb);
4312         NEW_BBLOCK (cfg, end_bb);
4313
4314         /* Do the assignment at the beginning, so the other assignment can be if converted */
4315         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4316         ins->type = STACK_OBJ;
4317         ins->klass = klass;
4318
4319         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4320         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4321
4322         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4323
4324         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4325                 g_assert (!context_used);
4326                 /* the is_null_bb target simply copies the input register to the output */
4327                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4328         } else {
4329                 int klass_reg = alloc_preg (cfg);
4330
4331                 if (klass->rank) {
4332                         int rank_reg = alloc_preg (cfg);
4333                         int eclass_reg = alloc_preg (cfg);
4334
4335                         g_assert (!context_used);
4336                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4337                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4338                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4339                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4340                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4341                         if (klass->cast_class == mono_defaults.object_class) {
4342                                 int parent_reg = alloc_preg (cfg);
4343                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4344                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4345                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4346                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4347                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4348                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4349                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4350                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4351                         } else if (klass->cast_class == mono_defaults.enum_class) {
4352                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4353                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4354                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4355                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4356                         } else {
4357                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4358                                         /* Check that the object is a vector too */
4359                                         int bounds_reg = alloc_preg (cfg);
4360                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4361                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4362                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4363                                 }
4364
4365                                 /* the is_null_bb target simply copies the input register to the output */
4366                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4367                         }
4368                 } else if (mono_class_is_nullable (klass)) {
4369                         g_assert (!context_used);
4370                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4371                         /* the is_null_bb target simply copies the input register to the output */
4372                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4373                 } else {
4374                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4375                                 g_assert (!context_used);
4376                                 /* the remoting code is broken, access the class for now */
4377                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4378                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4379                                         if (!vt) {
4380                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4381                                                 cfg->exception_ptr = klass;
4382                                                 return NULL;
4383                                         }
4384                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4385                                 } else {
4386                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4387                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4388                                 }
4389                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4390                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4391                         } else {
4392                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4393                                 /* the is_null_bb target simply copies the input register to the output */
4394                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4395                         }
4396                 }
4397         }
4398
4399         MONO_START_BB (cfg, false_bb);
4400
4401         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4402         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4403
4404         MONO_START_BB (cfg, is_null_bb);
4405
4406         MONO_START_BB (cfg, end_bb);
4407
4408         return ins;
4409 }
4410
4411 static MonoInst*
4412 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4413 {
4414         /* This opcode takes as input an object reference and a class, and returns:
4415         0) if the object is an instance of the class,
4416         1) if the object is not instance of the class,
4417         2) if the object is a proxy whose type cannot be determined */
4418
4419         MonoInst *ins;
4420 #ifndef DISABLE_REMOTING
4421         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4422 #else
4423         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4424 #endif
4425         int obj_reg = src->dreg;
4426         int dreg = alloc_ireg (cfg);
4427         int tmp_reg;
4428 #ifndef DISABLE_REMOTING
4429         int klass_reg = alloc_preg (cfg);
4430 #endif
4431
4432         NEW_BBLOCK (cfg, true_bb);
4433         NEW_BBLOCK (cfg, false_bb);
4434         NEW_BBLOCK (cfg, end_bb);
4435 #ifndef DISABLE_REMOTING
4436         NEW_BBLOCK (cfg, false2_bb);
4437         NEW_BBLOCK (cfg, no_proxy_bb);
4438 #endif
4439
4440         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4441         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4442
4443         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4444 #ifndef DISABLE_REMOTING
4445                 NEW_BBLOCK (cfg, interface_fail_bb);
4446 #endif
4447
4448                 tmp_reg = alloc_preg (cfg);
4449                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4450 #ifndef DISABLE_REMOTING
4451                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4452                 MONO_START_BB (cfg, interface_fail_bb);
4453                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4454                 
4455                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4456
4457                 tmp_reg = alloc_preg (cfg);
4458                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4459                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4460                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4461 #else
4462                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4463 #endif
4464         } else {
4465 #ifndef DISABLE_REMOTING
4466                 tmp_reg = alloc_preg (cfg);
4467                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4468                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4469
4470                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4471                 tmp_reg = alloc_preg (cfg);
4472                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4473                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4474
4475                 tmp_reg = alloc_preg (cfg);             
4476                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4477                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4478                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4479                 
4480                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4481                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4482
4483                 MONO_START_BB (cfg, no_proxy_bb);
4484
4485                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4486 #else
4487                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4488 #endif
4489         }
4490
4491         MONO_START_BB (cfg, false_bb);
4492
4493         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4494         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4495
4496 #ifndef DISABLE_REMOTING
4497         MONO_START_BB (cfg, false2_bb);
4498
4499         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4500         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4501 #endif
4502
4503         MONO_START_BB (cfg, true_bb);
4504
4505         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4506
4507         MONO_START_BB (cfg, end_bb);
4508
4509         /* FIXME: */
4510         MONO_INST_NEW (cfg, ins, OP_ICONST);
4511         ins->dreg = dreg;
4512         ins->type = STACK_I4;
4513
4514         return ins;
4515 }
4516
4517 static MonoInst*
4518 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4519 {
4520         /* This opcode takes as input an object reference and a class, and returns:
4521         0) if the object is an instance of the class,
4522         1) if the object is a proxy whose type cannot be determined
4523         an InvalidCastException exception is thrown otherwhise*/
4524         
4525         MonoInst *ins;
4526 #ifndef DISABLE_REMOTING
4527         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4528 #else
4529         MonoBasicBlock *ok_result_bb;
4530 #endif
4531         int obj_reg = src->dreg;
4532         int dreg = alloc_ireg (cfg);
4533         int tmp_reg = alloc_preg (cfg);
4534
4535 #ifndef DISABLE_REMOTING
4536         int klass_reg = alloc_preg (cfg);
4537         NEW_BBLOCK (cfg, end_bb);
4538 #endif
4539
4540         NEW_BBLOCK (cfg, ok_result_bb);
4541
4542         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4543         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4544
4545         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4546
4547         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4548 #ifndef DISABLE_REMOTING
4549                 NEW_BBLOCK (cfg, interface_fail_bb);
4550         
4551                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4552                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4553                 MONO_START_BB (cfg, interface_fail_bb);
4554                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4555
4556                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4557
4558                 tmp_reg = alloc_preg (cfg);             
4559                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4560                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4561                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4562                 
4563                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4564                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4565 #else
4566                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4567                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4568                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4569 #endif
4570         } else {
4571 #ifndef DISABLE_REMOTING
4572                 NEW_BBLOCK (cfg, no_proxy_bb);
4573
4574                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4575                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4576                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4577
4578                 tmp_reg = alloc_preg (cfg);
4579                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4580                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4581
4582                 tmp_reg = alloc_preg (cfg);
4583                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4584                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4585                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4586
4587                 NEW_BBLOCK (cfg, fail_1_bb);
4588                 
4589                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4590
4591                 MONO_START_BB (cfg, fail_1_bb);
4592
4593                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4594                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4595
4596                 MONO_START_BB (cfg, no_proxy_bb);
4597
4598                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4599 #else
4600                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4601 #endif
4602         }
4603
4604         MONO_START_BB (cfg, ok_result_bb);
4605
4606         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4607
4608 #ifndef DISABLE_REMOTING
4609         MONO_START_BB (cfg, end_bb);
4610 #endif
4611
4612         /* FIXME: */
4613         MONO_INST_NEW (cfg, ins, OP_ICONST);
4614         ins->dreg = dreg;
4615         ins->type = STACK_I4;
4616
4617         return ins;
4618 }
4619
4620 /*
4621  * Returns NULL and set the cfg exception on error.
4622  */
4623 static G_GNUC_UNUSED MonoInst*
4624 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4625 {
4626         MonoInst *ptr;
4627         int dreg;
4628         gpointer trampoline;
4629         MonoInst *obj, *method_ins, *tramp_ins;
4630         MonoDomain *domain;
4631         guint8 **code_slot;
4632         
4633         // FIXME reenable optimisation for virtual case
4634         if (virtual)
4635                 return NULL;
4636
4637         if (virtual) {
4638                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4639                 g_assert (invoke);
4640
4641                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4642                         return NULL;
4643         }
4644
4645         obj = handle_alloc (cfg, klass, FALSE, 0);
4646         if (!obj)
4647                 return NULL;
4648
4649         /* Inline the contents of mono_delegate_ctor */
4650
4651         /* Set target field */
4652         /* Optimize away setting of NULL target */
4653         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4654                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4655                 if (cfg->gen_write_barriers) {
4656                         dreg = alloc_preg (cfg);
4657                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4658                         emit_write_barrier (cfg, ptr, target);
4659                 }
4660         }
4661
4662         /* Set method field */
4663         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4664         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4665
4666         /* 
4667          * To avoid looking up the compiled code belonging to the target method
4668          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4669          * store it, and we fill it after the method has been compiled.
4670          */
4671         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4672                 MonoInst *code_slot_ins;
4673
4674                 if (context_used) {
4675                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4676                 } else {
4677                         domain = mono_domain_get ();
4678                         mono_domain_lock (domain);
4679                         if (!domain_jit_info (domain)->method_code_hash)
4680                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4681                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4682                         if (!code_slot) {
4683                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4684                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4685                         }
4686                         mono_domain_unlock (domain);
4687
4688                         if (cfg->compile_aot)
4689                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4690                         else
4691                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4692                 }
4693                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4694         }
4695
4696         if (cfg->compile_aot) {
4697                 MonoDelegateClassMethodPair *del_tramp;
4698
4699                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4700                 del_tramp->klass = klass;
4701                 del_tramp->method = context_used ? NULL : method;
4702                 del_tramp->virtual = virtual;
4703                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4704         } else {
4705                 if (virtual)
4706                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4707                 else
4708                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4709                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4710         }
4711
4712         /* Set invoke_impl field */
4713         if (virtual) {
4714                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4715         } else {
4716                 dreg = alloc_preg (cfg);
4717                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4718                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4719
4720                 dreg = alloc_preg (cfg);
4721                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4722                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4723         }
4724
4725         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4726
4727         return obj;
4728 }
4729
4730 static MonoInst*
4731 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4732 {
4733         MonoJitICallInfo *info;
4734
4735         /* Need to register the icall so it gets an icall wrapper */
4736         info = mono_get_array_new_va_icall (rank);
4737
4738         cfg->flags |= MONO_CFG_HAS_VARARGS;
4739
4740         /* mono_array_new_va () needs a vararg calling convention */
4741         cfg->disable_llvm = TRUE;
4742
4743         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4744         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4745 }
4746
4747 static void
4748 mono_emit_load_got_addr (MonoCompile *cfg)
4749 {
4750         MonoInst *getaddr, *dummy_use;
4751
4752         if (!cfg->got_var || cfg->got_var_allocated)
4753                 return;
4754
4755         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4756         getaddr->cil_code = cfg->header->code;
4757         getaddr->dreg = cfg->got_var->dreg;
4758
4759         /* Add it to the start of the first bblock */
4760         if (cfg->bb_entry->code) {
4761                 getaddr->next = cfg->bb_entry->code;
4762                 cfg->bb_entry->code = getaddr;
4763         }
4764         else
4765                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4766
4767         cfg->got_var_allocated = TRUE;
4768
4769         /* 
4770          * Add a dummy use to keep the got_var alive, since real uses might
4771          * only be generated by the back ends.
4772          * Add it to end_bblock, so the variable's lifetime covers the whole
4773          * method.
4774          * It would be better to make the usage of the got var explicit in all
4775          * cases when the backend needs it (i.e. calls, throw etc.), so this
4776          * wouldn't be needed.
4777          */
4778         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4779         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4780 }
4781
4782 static int inline_limit;
4783 static gboolean inline_limit_inited;
4784
4785 static gboolean
4786 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4787 {
4788         MonoMethodHeaderSummary header;
4789         MonoVTable *vtable;
4790 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4791         MonoMethodSignature *sig = mono_method_signature (method);
4792         int i;
4793 #endif
4794
4795         if (cfg->disable_inline)
4796                 return FALSE;
4797         if (cfg->generic_sharing_context)
4798                 return FALSE;
4799
4800         if (cfg->inline_depth > 10)
4801                 return FALSE;
4802
4803 #ifdef MONO_ARCH_HAVE_LMF_OPS
4804         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4805                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4806             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4807                 return TRUE;
4808 #endif
4809
4810
4811         if (!mono_method_get_header_summary (method, &header))
4812                 return FALSE;
4813
4814         /*runtime, icall and pinvoke are checked by summary call*/
4815         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4816             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4817             (mono_class_is_marshalbyref (method->klass)) ||
4818             header.has_clauses)
4819                 return FALSE;
4820
4821         /* also consider num_locals? */
4822         /* Do the size check early to avoid creating vtables */
4823         if (!inline_limit_inited) {
4824                 if (g_getenv ("MONO_INLINELIMIT"))
4825                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4826                 else
4827                         inline_limit = INLINE_LENGTH_LIMIT;
4828                 inline_limit_inited = TRUE;
4829         }
4830         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4831                 return FALSE;
4832
4833         /*
4834          * if we can initialize the class of the method right away, we do,
4835          * otherwise we don't allow inlining if the class needs initialization,
4836          * since it would mean inserting a call to mono_runtime_class_init()
4837          * inside the inlined code
4838          */
4839         if (!(cfg->opt & MONO_OPT_SHARED)) {
4840                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4841                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4842                         vtable = mono_class_vtable (cfg->domain, method->klass);
4843                         if (!vtable)
4844                                 return FALSE;
4845                         if (!cfg->compile_aot)
4846                                 mono_runtime_class_init (vtable);
4847                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4848                         if (cfg->run_cctors && method->klass->has_cctor) {
4849                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4850                                 if (!method->klass->runtime_info)
4851                                         /* No vtable created yet */
4852                                         return FALSE;
4853                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4854                                 if (!vtable)
4855                                         return FALSE;
4856                                 /* This makes so that inline cannot trigger */
4857                                 /* .cctors: too many apps depend on them */
4858                                 /* running with a specific order... */
4859                                 if (! vtable->initialized)
4860                                         return FALSE;
4861                                 mono_runtime_class_init (vtable);
4862                         }
4863                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4864                         if (!method->klass->runtime_info)
4865                                 /* No vtable created yet */
4866                                 return FALSE;
4867                         vtable = mono_class_vtable (cfg->domain, method->klass);
4868                         if (!vtable)
4869                                 return FALSE;
4870                         if (!vtable->initialized)
4871                                 return FALSE;
4872                 }
4873         } else {
4874                 /* 
4875                  * If we're compiling for shared code
4876                  * the cctor will need to be run at aot method load time, for example,
4877                  * or at the end of the compilation of the inlining method.
4878                  */
4879                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4880                         return FALSE;
4881         }
4882
4883         /*
4884          * CAS - do not inline methods with declarative security
4885          * Note: this has to be before any possible return TRUE;
4886          */
4887         if (mono_security_method_has_declsec (method))
4888                 return FALSE;
4889
4890 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4891         if (mono_arch_is_soft_float ()) {
4892                 /* FIXME: */
4893                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4894                         return FALSE;
4895                 for (i = 0; i < sig->param_count; ++i)
4896                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4897                                 return FALSE;
4898         }
4899 #endif
4900
4901         if (g_list_find (cfg->dont_inline, method))
4902                 return FALSE;
4903
4904         return TRUE;
4905 }
4906
4907 static gboolean
4908 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4909 {
4910         if (!cfg->compile_aot) {
4911                 g_assert (vtable);
4912                 if (vtable->initialized)
4913                         return FALSE;
4914         }
4915
4916         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4917                 if (cfg->method == method)
4918                         return FALSE;
4919         }
4920
4921         if (!mono_class_needs_cctor_run (klass, method))
4922                 return FALSE;
4923
4924         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4925                 /* The initialization is already done before the method is called */
4926                 return FALSE;
4927
4928         return TRUE;
4929 }
4930
4931 static MonoInst*
4932 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4933 {
4934         MonoInst *ins;
4935         guint32 size;
4936         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4937         int context_used;
4938
4939         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
4940                 size = -1;
4941         } else {
4942                 mono_class_init (klass);
4943                 size = mono_class_array_element_size (klass);
4944         }
4945
4946         mult_reg = alloc_preg (cfg);
4947         array_reg = arr->dreg;
4948         index_reg = index->dreg;
4949
4950 #if SIZEOF_REGISTER == 8
4951         /* The array reg is 64 bits but the index reg is only 32 */
4952         if (COMPILE_LLVM (cfg)) {
4953                 /* Not needed */
4954                 index2_reg = index_reg;
4955         } else {
4956                 index2_reg = alloc_preg (cfg);
4957                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4958         }
4959 #else
4960         if (index->type == STACK_I8) {
4961                 index2_reg = alloc_preg (cfg);
4962                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4963         } else {
4964                 index2_reg = index_reg;
4965         }
4966 #endif
4967
4968         if (bcheck)
4969                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4970
4971 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4972         if (size == 1 || size == 2 || size == 4 || size == 8) {
4973                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4974
4975                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
4976                 ins->klass = mono_class_get_element_class (klass);
4977                 ins->type = STACK_MP;
4978
4979                 return ins;
4980         }
4981 #endif          
4982
4983         add_reg = alloc_ireg_mp (cfg);
4984
4985         if (size == -1) {
4986                 MonoInst *rgctx_ins;
4987
4988                 /* gsharedvt */
4989                 g_assert (cfg->generic_sharing_context);
4990                 context_used = mini_class_check_context_used (cfg, klass);
4991                 g_assert (context_used);
4992                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4993                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4994         } else {
4995                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4996         }
4997         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4998         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
4999         ins->klass = mono_class_get_element_class (klass);
5000         ins->type = STACK_MP;
5001         MONO_ADD_INS (cfg->cbb, ins);
5002
5003         return ins;
5004 }
5005
5006 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5007 static MonoInst*
5008 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5009 {
5010         int bounds_reg = alloc_preg (cfg);
5011         int add_reg = alloc_ireg_mp (cfg);
5012         int mult_reg = alloc_preg (cfg);
5013         int mult2_reg = alloc_preg (cfg);
5014         int low1_reg = alloc_preg (cfg);
5015         int low2_reg = alloc_preg (cfg);
5016         int high1_reg = alloc_preg (cfg);
5017         int high2_reg = alloc_preg (cfg);
5018         int realidx1_reg = alloc_preg (cfg);
5019         int realidx2_reg = alloc_preg (cfg);
5020         int sum_reg = alloc_preg (cfg);
5021         int index1, index2, tmpreg;
5022         MonoInst *ins;
5023         guint32 size;
5024
5025         mono_class_init (klass);
5026         size = mono_class_array_element_size (klass);
5027
5028         index1 = index_ins1->dreg;
5029         index2 = index_ins2->dreg;
5030
5031 #if SIZEOF_REGISTER == 8
5032         /* The array reg is 64 bits but the index reg is only 32 */
5033         if (COMPILE_LLVM (cfg)) {
5034                 /* Not needed */
5035         } else {
5036                 tmpreg = alloc_preg (cfg);
5037                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5038                 index1 = tmpreg;
5039                 tmpreg = alloc_preg (cfg);
5040                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5041                 index2 = tmpreg;
5042         }
5043 #else
5044         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5045         tmpreg = -1;
5046 #endif
5047
5048         /* range checking */
5049         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5050                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5051
5052         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5053                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5054         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5055         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5056                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5057         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5058         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5059
5060         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5061                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5062         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5063         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5064                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5065         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5066         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5067
5068         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5069         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5070         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5071         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5072         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5073
5074         ins->type = STACK_MP;
5075         ins->klass = klass;
5076         MONO_ADD_INS (cfg->cbb, ins);
5077
5078         return ins;
5079 }
5080 #endif
5081
5082 static MonoInst*
5083 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5084 {
5085         int rank;
5086         MonoInst *addr;
5087         MonoMethod *addr_method;
5088         int element_size;
5089
5090         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5091
5092         if (rank == 1)
5093                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
5094
5095 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5096         /* emit_ldelema_2 depends on OP_LMUL */
5097         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
5098                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
5099         }
5100 #endif
5101
5102         element_size = mono_class_array_element_size (cmethod->klass->element_class);
5103         addr_method = mono_marshal_get_array_address (rank, element_size);
5104         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5105
5106         return addr;
5107 }
5108
5109 static MonoBreakPolicy
5110 always_insert_breakpoint (MonoMethod *method)
5111 {
5112         return MONO_BREAK_POLICY_ALWAYS;
5113 }
5114
5115 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5116
5117 /**
5118  * mono_set_break_policy:
5119  * policy_callback: the new callback function
5120  *
5121  * Allow embedders to decide wherther to actually obey breakpoint instructions
5122  * (both break IL instructions and Debugger.Break () method calls), for example
5123  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5124  * untrusted or semi-trusted code.
5125  *
5126  * @policy_callback will be called every time a break point instruction needs to
5127  * be inserted with the method argument being the method that calls Debugger.Break()
5128  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5129  * if it wants the breakpoint to not be effective in the given method.
5130  * #MONO_BREAK_POLICY_ALWAYS is the default.
5131  */
5132 void
5133 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5134 {
5135         if (policy_callback)
5136                 break_policy_func = policy_callback;
5137         else
5138                 break_policy_func = always_insert_breakpoint;
5139 }
5140
5141 static gboolean
5142 should_insert_brekpoint (MonoMethod *method) {
5143         switch (break_policy_func (method)) {
5144         case MONO_BREAK_POLICY_ALWAYS:
5145                 return TRUE;
5146         case MONO_BREAK_POLICY_NEVER:
5147                 return FALSE;
5148         case MONO_BREAK_POLICY_ON_DBG:
5149                 g_warning ("mdb no longer supported");
5150                 return FALSE;
5151         default:
5152                 g_warning ("Incorrect value returned from break policy callback");
5153                 return FALSE;
5154         }
5155 }
5156
5157 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5158 static MonoInst*
5159 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5160 {
5161         MonoInst *addr, *store, *load;
5162         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5163
5164         /* the bounds check is already done by the callers */
5165         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5166         if (is_set) {
5167                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5168                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5169                 if (mini_type_is_reference (cfg, fsig->params [2]))
5170                         emit_write_barrier (cfg, addr, load);
5171         } else {
5172                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5173                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5174         }
5175         return store;
5176 }
5177
5178
5179 static gboolean
5180 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5181 {
5182         return mini_type_is_reference (cfg, &klass->byval_arg);
5183 }
5184
5185 static MonoInst*
5186 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5187 {
5188         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5189                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5190                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5191                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5192                 MonoInst *iargs [3];
5193
5194                 if (!helper->slot)
5195                         mono_class_setup_vtable (obj_array);
5196                 g_assert (helper->slot);
5197
5198                 if (sp [0]->type != STACK_OBJ)
5199                         return NULL;
5200                 if (sp [2]->type != STACK_OBJ)
5201                         return NULL;
5202
5203                 iargs [2] = sp [2];
5204                 iargs [1] = sp [1];
5205                 iargs [0] = sp [0];
5206
5207                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5208         } else {
5209                 MonoInst *ins;
5210
5211                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5212                         MonoInst *addr;
5213
5214                         // FIXME-VT: OP_ICONST optimization
5215                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5216                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5217                         ins->opcode = OP_STOREV_MEMBASE;
5218                 } else if (sp [1]->opcode == OP_ICONST) {
5219                         int array_reg = sp [0]->dreg;
5220                         int index_reg = sp [1]->dreg;
5221                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5222
5223                         if (safety_checks)
5224                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5225                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5226                 } else {
5227                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5228                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5229                         if (generic_class_is_reference_type (cfg, klass))
5230                                 emit_write_barrier (cfg, addr, sp [2]);
5231                 }
5232                 return ins;
5233         }
5234 }
5235
5236 static MonoInst*
5237 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5238 {
5239         MonoClass *eklass;
5240         
5241         if (is_set)
5242                 eklass = mono_class_from_mono_type (fsig->params [2]);
5243         else
5244                 eklass = mono_class_from_mono_type (fsig->ret);
5245
5246         if (is_set) {
5247                 return emit_array_store (cfg, eklass, args, FALSE);
5248         } else {
5249                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5250                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5251                 return ins;
5252         }
5253 }
5254
5255 static gboolean
5256 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5257 {
5258         uint32_t align;
5259
5260         //Only allow for valuetypes
5261         if (!param_klass->valuetype || !return_klass->valuetype)
5262                 return FALSE;
5263
5264         //That are blitable
5265         if (param_klass->has_references || return_klass->has_references)
5266                 return FALSE;
5267
5268         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5269         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5270                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5271                 return FALSE;
5272
5273         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5274                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5275                 return FALSE;
5276
5277         //And have the same size
5278         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5279                 return FALSE;
5280         return TRUE;
5281 }
5282
5283 static MonoInst*
5284 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5285 {
5286         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5287         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5288
5289         //Valuetypes that are semantically equivalent
5290         if (is_unsafe_mov_compatible (param_klass, return_klass))
5291                 return args [0];
5292
5293         //Arrays of valuetypes that are semantically equivalent
5294         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5295                 return args [0];
5296
5297         return NULL;
5298 }
5299
5300 static MonoInst*
5301 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5302 {
5303 #ifdef MONO_ARCH_SIMD_INTRINSICS
5304         MonoInst *ins = NULL;
5305
5306         if (cfg->opt & MONO_OPT_SIMD) {
5307                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5308                 if (ins)
5309                         return ins;
5310         }
5311 #endif
5312
5313         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5314 }
5315
5316 static MonoInst*
5317 emit_memory_barrier (MonoCompile *cfg, int kind)
5318 {
5319         MonoInst *ins = NULL;
5320         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5321         MONO_ADD_INS (cfg->cbb, ins);
5322         ins->backend.memory_barrier_kind = kind;
5323
5324         return ins;
5325 }
5326
5327 static MonoInst*
5328 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5329 {
5330         MonoInst *ins = NULL;
5331         int opcode = 0;
5332
5333         /* The LLVM backend supports these intrinsics */
5334         if (cmethod->klass == mono_defaults.math_class) {
5335                 if (strcmp (cmethod->name, "Sin") == 0) {
5336                         opcode = OP_SIN;
5337                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5338                         opcode = OP_COS;
5339                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5340                         opcode = OP_SQRT;
5341                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5342                         opcode = OP_ABS;
5343                 }
5344
5345                 if (opcode) {
5346                         MONO_INST_NEW (cfg, ins, opcode);
5347                         ins->type = STACK_R8;
5348                         ins->dreg = mono_alloc_freg (cfg);
5349                         ins->sreg1 = args [0]->dreg;
5350                         MONO_ADD_INS (cfg->cbb, ins);
5351                 }
5352
5353                 opcode = 0;
5354                 if (cfg->opt & MONO_OPT_CMOV) {
5355                         if (strcmp (cmethod->name, "Min") == 0) {
5356                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5357                                         opcode = OP_IMIN;
5358                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5359                                         opcode = OP_IMIN_UN;
5360                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5361                                         opcode = OP_LMIN;
5362                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5363                                         opcode = OP_LMIN_UN;
5364                         } else if (strcmp (cmethod->name, "Max") == 0) {
5365                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5366                                         opcode = OP_IMAX;
5367                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5368                                         opcode = OP_IMAX_UN;
5369                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5370                                         opcode = OP_LMAX;
5371                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5372                                         opcode = OP_LMAX_UN;
5373                         }
5374                 }
5375
5376                 if (opcode) {
5377                         MONO_INST_NEW (cfg, ins, opcode);
5378                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5379                         ins->dreg = mono_alloc_ireg (cfg);
5380                         ins->sreg1 = args [0]->dreg;
5381                         ins->sreg2 = args [1]->dreg;
5382                         MONO_ADD_INS (cfg->cbb, ins);
5383                 }
5384         }
5385
5386         return ins;
5387 }
5388
5389 static MonoInst*
5390 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5391 {
5392         if (cmethod->klass == mono_defaults.array_class) {
5393                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5394                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5395                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5396                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5397                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5398                         return emit_array_unsafe_mov (cfg, fsig, args);
5399         }
5400
5401         return NULL;
5402 }
5403
5404 static MonoInst*
5405 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5406 {
5407         MonoInst *ins = NULL;
5408         
5409         static MonoClass *runtime_helpers_class = NULL;
5410         if (! runtime_helpers_class)
5411                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5412                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5413
5414         if (cmethod->klass == mono_defaults.string_class) {
5415                 if (strcmp (cmethod->name, "get_Chars") == 0) {
5416                         int dreg = alloc_ireg (cfg);
5417                         int index_reg = alloc_preg (cfg);
5418                         int mult_reg = alloc_preg (cfg);
5419                         int add_reg = alloc_preg (cfg);
5420
5421 #if SIZEOF_REGISTER == 8
5422                         /* The array reg is 64 bits but the index reg is only 32 */
5423                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5424 #else
5425                         index_reg = args [1]->dreg;
5426 #endif  
5427                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5428
5429 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5430                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5431                         add_reg = ins->dreg;
5432                         /* Avoid a warning */
5433                         mult_reg = 0;
5434                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5435                                                                    add_reg, 0);
5436 #else
5437                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5438                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5439                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5440                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5441 #endif
5442                         type_from_op (ins, NULL, NULL);
5443                         return ins;
5444                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5445                         int dreg = alloc_ireg (cfg);
5446                         /* Decompose later to allow more optimizations */
5447                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5448                         ins->type = STACK_I4;
5449                         ins->flags |= MONO_INST_FAULT;
5450                         cfg->cbb->has_array_access = TRUE;
5451                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5452
5453                         return ins;
5454                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5455                         int mult_reg = alloc_preg (cfg);
5456                         int add_reg = alloc_preg (cfg);
5457
5458                         /* The corlib functions check for oob already. */
5459                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5460                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5461                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, MONO_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5462                         return cfg->cbb->last_ins;
5463                 } else 
5464                         return NULL;
5465         } else if (cmethod->klass == mono_defaults.object_class) {
5466
5467                 if (strcmp (cmethod->name, "GetType") == 0) {
5468                         int dreg = alloc_ireg_ref (cfg);
5469                         int vt_reg = alloc_preg (cfg);
5470                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5471                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5472                         type_from_op (ins, NULL, NULL);
5473
5474                         return ins;
5475 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5476                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5477                         int dreg = alloc_ireg (cfg);
5478                         int t1 = alloc_ireg (cfg);
5479         
5480                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5481                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5482                         ins->type = STACK_I4;
5483
5484                         return ins;
5485 #endif
5486                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5487                         MONO_INST_NEW (cfg, ins, OP_NOP);
5488                         MONO_ADD_INS (cfg->cbb, ins);
5489                         return ins;
5490                 } else
5491                         return NULL;
5492         } else if (cmethod->klass == mono_defaults.array_class) {
5493                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5494                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5495
5496 #ifndef MONO_BIG_ARRAYS
5497                 /*
5498                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5499                  * Array methods.
5500                  */
5501                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5502                         int dreg = alloc_ireg (cfg);
5503                         int bounds_reg = alloc_ireg_mp (cfg);
5504                         MonoBasicBlock *end_bb, *szarray_bb;
5505                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5506
5507                         NEW_BBLOCK (cfg, end_bb);
5508                         NEW_BBLOCK (cfg, szarray_bb);
5509
5510                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5511                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5512                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5513                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5514                         /* Non-szarray case */
5515                         if (get_length)
5516                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5517                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5518                         else
5519                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5520                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5521                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5522                         MONO_START_BB (cfg, szarray_bb);
5523                         /* Szarray case */
5524                         if (get_length)
5525                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5526                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5527                         else
5528                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5529                         MONO_START_BB (cfg, end_bb);
5530
5531                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5532                         ins->type = STACK_I4;
5533                         
5534                         return ins;
5535                 }
5536 #endif
5537
5538                 if (cmethod->name [0] != 'g')
5539                         return NULL;
5540
5541                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5542                         int dreg = alloc_ireg (cfg);
5543                         int vtable_reg = alloc_preg (cfg);
5544                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5545                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5546                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5547                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5548                         type_from_op (ins, NULL, NULL);
5549
5550                         return ins;
5551                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5552                         int dreg = alloc_ireg (cfg);
5553
5554                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5555                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5556                         type_from_op (ins, NULL, NULL);
5557
5558                         return ins;
5559                 } else
5560                         return NULL;
5561         } else if (cmethod->klass == runtime_helpers_class) {
5562
5563                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5564                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5565                         return ins;
5566                 } else
5567                         return NULL;
5568         } else if (cmethod->klass == mono_defaults.thread_class) {
5569                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5570                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5571                         MONO_ADD_INS (cfg->cbb, ins);
5572                         return ins;
5573                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5574                         return emit_memory_barrier (cfg, FullBarrier);
5575                 }
5576         } else if (cmethod->klass == mono_defaults.monitor_class) {
5577 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5578                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5579                         MonoCallInst *call;
5580
5581                         if (COMPILE_LLVM (cfg)) {
5582                                 /* 
5583                                  * Pass the argument normally, the LLVM backend will handle the
5584                                  * calling convention problems.
5585                                  */
5586                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5587                         } else {
5588                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5589                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5590                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5591                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5592                         }
5593
5594                         return (MonoInst*)call;
5595 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
5596                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5597                         MonoCallInst *call;
5598
5599                         if (COMPILE_LLVM (cfg)) {
5600                                 /*
5601                                  * Pass the argument normally, the LLVM backend will handle the
5602                                  * calling convention problems.
5603                                  */
5604                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
5605                         } else {
5606                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
5607                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5608                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5609                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
5610                         }
5611
5612                         return (MonoInst*)call;
5613 #endif
5614                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5615                         MonoCallInst *call;
5616
5617                         if (COMPILE_LLVM (cfg)) {
5618                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5619                         } else {
5620                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5621                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5622                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5623                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5624                         }
5625
5626                         return (MonoInst*)call;
5627                 }
5628 #endif
5629         } else if (cmethod->klass->image == mono_defaults.corlib &&
5630                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5631                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5632                 ins = NULL;
5633
5634 #if SIZEOF_REGISTER == 8
5635                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5636                         MonoInst *load_ins;
5637
5638                         emit_memory_barrier (cfg, FullBarrier);
5639
5640                         /* 64 bit reads are already atomic */
5641                         MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5642                         load_ins->dreg = mono_alloc_preg (cfg);
5643                         load_ins->inst_basereg = args [0]->dreg;
5644                         load_ins->inst_offset = 0;
5645                         MONO_ADD_INS (cfg->cbb, load_ins);
5646
5647                         emit_memory_barrier (cfg, FullBarrier);
5648
5649                         ins = load_ins;
5650                 }
5651 #endif
5652
5653                 if (strcmp (cmethod->name, "Increment") == 0) {
5654                         MonoInst *ins_iconst;
5655                         guint32 opcode = 0;
5656
5657                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5658                                 opcode = OP_ATOMIC_ADD_I4;
5659                                 cfg->has_atomic_add_i4 = TRUE;
5660                         }
5661 #if SIZEOF_REGISTER == 8
5662                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5663                                 opcode = OP_ATOMIC_ADD_I8;
5664 #endif
5665                         if (opcode) {
5666                                 if (!mono_arch_opcode_supported (opcode))
5667                                         return NULL;
5668                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5669                                 ins_iconst->inst_c0 = 1;
5670                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5671                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5672
5673                                 MONO_INST_NEW (cfg, ins, opcode);
5674                                 ins->dreg = mono_alloc_ireg (cfg);
5675                                 ins->inst_basereg = args [0]->dreg;
5676                                 ins->inst_offset = 0;
5677                                 ins->sreg2 = ins_iconst->dreg;
5678                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5679                                 MONO_ADD_INS (cfg->cbb, ins);
5680                         }
5681                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5682                         MonoInst *ins_iconst;
5683                         guint32 opcode = 0;
5684
5685                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5686                                 opcode = OP_ATOMIC_ADD_I4;
5687                                 cfg->has_atomic_add_i4 = TRUE;
5688                         }
5689 #if SIZEOF_REGISTER == 8
5690                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5691                                 opcode = OP_ATOMIC_ADD_I8;
5692 #endif
5693                         if (opcode) {
5694                                 if (!mono_arch_opcode_supported (opcode))
5695                                         return NULL;
5696                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5697                                 ins_iconst->inst_c0 = -1;
5698                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5699                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5700
5701                                 MONO_INST_NEW (cfg, ins, opcode);
5702                                 ins->dreg = mono_alloc_ireg (cfg);
5703                                 ins->inst_basereg = args [0]->dreg;
5704                                 ins->inst_offset = 0;
5705                                 ins->sreg2 = ins_iconst->dreg;
5706                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5707                                 MONO_ADD_INS (cfg->cbb, ins);
5708                         }
5709                 } else if (strcmp (cmethod->name, "Add") == 0) {
5710                         guint32 opcode = 0;
5711
5712                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5713                                 opcode = OP_ATOMIC_ADD_I4;
5714                                 cfg->has_atomic_add_i4 = TRUE;
5715                         }
5716 #if SIZEOF_REGISTER == 8
5717                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5718                                 opcode = OP_ATOMIC_ADD_I8;
5719 #endif
5720                         if (opcode) {
5721                                 if (!mono_arch_opcode_supported (opcode))
5722                                         return NULL;
5723                                 MONO_INST_NEW (cfg, ins, opcode);
5724                                 ins->dreg = mono_alloc_ireg (cfg);
5725                                 ins->inst_basereg = args [0]->dreg;
5726                                 ins->inst_offset = 0;
5727                                 ins->sreg2 = args [1]->dreg;
5728                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5729                                 MONO_ADD_INS (cfg->cbb, ins);
5730                         }
5731                 }
5732
5733                 if (strcmp (cmethod->name, "Exchange") == 0) {
5734                         guint32 opcode;
5735                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5736
5737                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5738                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5739                                 cfg->has_atomic_exchange_i4 = TRUE;
5740                         }
5741 #if SIZEOF_REGISTER == 8
5742                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5743                                         (fsig->params [0]->type == MONO_TYPE_I))
5744                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5745 #else
5746                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I)) {
5747                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5748                                 cfg->has_atomic_exchange_i4 = TRUE;
5749                         }
5750 #endif
5751                         else
5752                                 return NULL;
5753
5754                         if (!mono_arch_opcode_supported (opcode))
5755                                 return NULL;
5756
5757                         MONO_INST_NEW (cfg, ins, opcode);
5758                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5759                         ins->inst_basereg = args [0]->dreg;
5760                         ins->inst_offset = 0;
5761                         ins->sreg2 = args [1]->dreg;
5762                         MONO_ADD_INS (cfg->cbb, ins);
5763
5764                         switch (fsig->params [0]->type) {
5765                         case MONO_TYPE_I4:
5766                                 ins->type = STACK_I4;
5767                                 break;
5768                         case MONO_TYPE_I8:
5769                         case MONO_TYPE_I:
5770                                 ins->type = STACK_I8;
5771                                 break;
5772                         case MONO_TYPE_OBJECT:
5773                                 ins->type = STACK_OBJ;
5774                                 break;
5775                         default:
5776                                 g_assert_not_reached ();
5777                         }
5778
5779                         if (cfg->gen_write_barriers && is_ref)
5780                                 emit_write_barrier (cfg, args [0], args [1]);
5781                 }
5782
5783                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5784                         int size = 0;
5785                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5786                         if (fsig->params [1]->type == MONO_TYPE_I4)
5787                                 size = 4;
5788                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5789                                 size = sizeof (gpointer);
5790                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5791                                 size = 8;
5792                         if (size == 4) {
5793                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5794                                         return NULL;
5795                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5796                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5797                                 ins->sreg1 = args [0]->dreg;
5798                                 ins->sreg2 = args [1]->dreg;
5799                                 ins->sreg3 = args [2]->dreg;
5800                                 ins->type = STACK_I4;
5801                                 MONO_ADD_INS (cfg->cbb, ins);
5802                                 cfg->has_atomic_cas_i4 = TRUE;
5803                         } else if (size == 8) {
5804                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I8))
5805                                         return NULL;
5806                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5807                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5808                                 ins->sreg1 = args [0]->dreg;
5809                                 ins->sreg2 = args [1]->dreg;
5810                                 ins->sreg3 = args [2]->dreg;
5811                                 ins->type = STACK_I8;
5812                                 MONO_ADD_INS (cfg->cbb, ins);
5813                         } else {
5814                                 /* g_assert_not_reached (); */
5815                         }
5816                         if (cfg->gen_write_barriers && is_ref)
5817                                 emit_write_barrier (cfg, args [0], args [1]);
5818                 }
5819
5820                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5821                         ins = emit_memory_barrier (cfg, FullBarrier);
5822
5823                 if (ins)
5824                         return ins;
5825         } else if (cmethod->klass->image == mono_defaults.corlib) {
5826                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5827                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5828                         if (should_insert_brekpoint (cfg->method)) {
5829                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5830                         } else {
5831                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5832                                 MONO_ADD_INS (cfg->cbb, ins);
5833                         }
5834                         return ins;
5835                 }
5836                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5837                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5838 #ifdef TARGET_WIN32
5839                         EMIT_NEW_ICONST (cfg, ins, 1);
5840 #else
5841                         EMIT_NEW_ICONST (cfg, ins, 0);
5842 #endif
5843                         return ins;
5844                 }
5845         } else if (cmethod->klass == mono_defaults.math_class) {
5846                 /* 
5847                  * There is general branches code for Min/Max, but it does not work for 
5848                  * all inputs:
5849                  * http://everything2.com/?node_id=1051618
5850                  */
5851         } 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)) {
5852 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5853                 MonoInst *pi;
5854                 MonoJumpInfoToken *ji;
5855                 MonoString *s;
5856
5857                 cfg->disable_llvm = TRUE;
5858
5859                 if (args [0]->opcode == OP_GOT_ENTRY) {
5860                         pi = args [0]->inst_p1;
5861                         g_assert (pi->opcode == OP_PATCH_INFO);
5862                         g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
5863                         ji = pi->inst_p0;
5864                 } else {
5865                         g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
5866                         ji = args [0]->inst_p0;
5867                 }
5868
5869                 NULLIFY_INS (args [0]);
5870
5871                 // FIXME: Ugly
5872                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5873                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5874                 ins->dreg = mono_alloc_ireg (cfg);
5875                 // FIXME: Leaks
5876                 ins->inst_p0 = mono_string_to_utf8 (s);
5877                 MONO_ADD_INS (cfg->cbb, ins);
5878                 return ins;
5879 #endif
5880         }
5881
5882 #ifdef MONO_ARCH_SIMD_INTRINSICS
5883         if (cfg->opt & MONO_OPT_SIMD) {
5884                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5885                 if (ins)
5886                         return ins;
5887         }
5888 #endif
5889
5890         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5891         if (ins)
5892                 return ins;
5893
5894         if (COMPILE_LLVM (cfg)) {
5895                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5896                 if (ins)
5897                         return ins;
5898         }
5899
5900         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5901 }
5902
5903 /*
5904  * This entry point could be used later for arbitrary method
5905  * redirection.
5906  */
5907 inline static MonoInst*
5908 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5909                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5910 {
5911         if (method->klass == mono_defaults.string_class) {
5912                 /* managed string allocation support */
5913                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5914                         MonoInst *iargs [2];
5915                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5916                         MonoMethod *managed_alloc = NULL;
5917
5918                         g_assert (vtable); /*Should not fail since it System.String*/
5919 #ifndef MONO_CROSS_COMPILE
5920                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
5921 #endif
5922                         if (!managed_alloc)
5923                                 return NULL;
5924                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5925                         iargs [1] = args [0];
5926                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5927                 }
5928         }
5929         return NULL;
5930 }
5931
5932 static void
5933 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5934 {
5935         MonoInst *store, *temp;
5936         int i;
5937
5938         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5939                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5940
5941                 /*
5942                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5943                  * would be different than the MonoInst's used to represent arguments, and
5944                  * the ldelema implementation can't deal with that.
5945                  * Solution: When ldelema is used on an inline argument, create a var for 
5946                  * it, emit ldelema on that var, and emit the saving code below in
5947                  * inline_method () if needed.
5948                  */
5949                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5950                 cfg->args [i] = temp;
5951                 /* This uses cfg->args [i] which is set by the preceeding line */
5952                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5953                 store->cil_code = sp [0]->cil_code;
5954                 sp++;
5955         }
5956 }
5957
5958 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5959 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5960
5961 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5962 static gboolean
5963 check_inline_called_method_name_limit (MonoMethod *called_method)
5964 {
5965         int strncmp_result;
5966         static const char *limit = NULL;
5967         
5968         if (limit == NULL) {
5969                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5970
5971                 if (limit_string != NULL)
5972                         limit = limit_string;
5973                 else
5974                         limit = "";
5975         }
5976
5977         if (limit [0] != '\0') {
5978                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5979
5980                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5981                 g_free (called_method_name);
5982         
5983                 //return (strncmp_result <= 0);
5984                 return (strncmp_result == 0);
5985         } else {
5986                 return TRUE;
5987         }
5988 }
5989 #endif
5990
5991 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5992 static gboolean
5993 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5994 {
5995         int strncmp_result;
5996         static const char *limit = NULL;
5997         
5998         if (limit == NULL) {
5999                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6000                 if (limit_string != NULL) {
6001                         limit = limit_string;
6002                 } else {
6003                         limit = "";
6004                 }
6005         }
6006
6007         if (limit [0] != '\0') {
6008                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6009
6010                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6011                 g_free (caller_method_name);
6012         
6013                 //return (strncmp_result <= 0);
6014                 return (strncmp_result == 0);
6015         } else {
6016                 return TRUE;
6017         }
6018 }
6019 #endif
6020
6021 static void
6022 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6023 {
6024         static double r8_0 = 0.0;
6025         MonoInst *ins;
6026         int t;
6027
6028         rtype = mini_replace_type (rtype);
6029         t = rtype->type;
6030
6031         if (rtype->byref) {
6032                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6033         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6034                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6035         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6036                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6037         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6038                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6039                 ins->type = STACK_R8;
6040                 ins->inst_p0 = (void*)&r8_0;
6041                 ins->dreg = dreg;
6042                 MONO_ADD_INS (cfg->cbb, ins);
6043         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6044                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6045                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6046         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6047                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6048         } else {
6049                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6050         }
6051 }
6052
6053 static void
6054 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6055 {
6056         int t;
6057
6058         rtype = mini_replace_type (rtype);
6059         t = rtype->type;
6060
6061         if (rtype->byref) {
6062                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6063         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6064                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6065         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6066                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6067         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6068                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6069         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6070                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6071                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6072         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6073                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6074         } else {
6075                 emit_init_rvar (cfg, dreg, rtype);
6076         }
6077 }
6078
6079 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6080 static void
6081 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6082 {
6083         MonoInst *var = cfg->locals [local];
6084         if (COMPILE_SOFT_FLOAT (cfg)) {
6085                 MonoInst *store;
6086                 int reg = alloc_dreg (cfg, var->type);
6087                 emit_init_rvar (cfg, reg, type);
6088                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6089         } else {
6090                 if (init)
6091                         emit_init_rvar (cfg, var->dreg, type);
6092                 else
6093                         emit_dummy_init_rvar (cfg, var->dreg, type);
6094         }
6095 }
6096
6097 /*
6098  * inline_method:
6099  *
6100  *   Return the cost of inlining CMETHOD.
6101  */
6102 static int
6103 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6104                            guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
6105 {
6106         MonoInst *ins, *rvar = NULL;
6107         MonoMethodHeader *cheader;
6108         MonoBasicBlock *ebblock, *sbblock;
6109         int i, costs;
6110         MonoMethod *prev_inlined_method;
6111         MonoInst **prev_locals, **prev_args;
6112         MonoType **prev_arg_types;
6113         guint prev_real_offset;
6114         GHashTable *prev_cbb_hash;
6115         MonoBasicBlock **prev_cil_offset_to_bb;
6116         MonoBasicBlock *prev_cbb;
6117         unsigned char* prev_cil_start;
6118         guint32 prev_cil_offset_to_bb_len;
6119         MonoMethod *prev_current_method;
6120         MonoGenericContext *prev_generic_context;
6121         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6122
6123         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6124
6125 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6126         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6127                 return 0;
6128 #endif
6129 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6130         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6131                 return 0;
6132 #endif
6133
6134         if (cfg->verbose_level > 2)
6135                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6136
6137         if (!cmethod->inline_info) {
6138                 cfg->stat_inlineable_methods++;
6139                 cmethod->inline_info = 1;
6140         }
6141
6142         /* allocate local variables */
6143         cheader = mono_method_get_header (cmethod);
6144
6145         if (cheader == NULL || mono_loader_get_last_error ()) {
6146                 MonoLoaderError *error = mono_loader_get_last_error ();
6147
6148                 if (cheader)
6149                         mono_metadata_free_mh (cheader);
6150                 if (inline_always && error)
6151                         mono_cfg_set_exception (cfg, error->exception_type);
6152
6153                 mono_loader_clear_error ();
6154                 return 0;
6155         }
6156
6157         /*Must verify before creating locals as it can cause the JIT to assert.*/
6158         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6159                 mono_metadata_free_mh (cheader);
6160                 return 0;
6161         }
6162
6163         /* allocate space to store the return value */
6164         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6165                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6166         }
6167
6168         prev_locals = cfg->locals;
6169         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6170         for (i = 0; i < cheader->num_locals; ++i)
6171                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6172
6173         /* allocate start and end blocks */
6174         /* This is needed so if the inline is aborted, we can clean up */
6175         NEW_BBLOCK (cfg, sbblock);
6176         sbblock->real_offset = real_offset;
6177
6178         NEW_BBLOCK (cfg, ebblock);
6179         ebblock->block_num = cfg->num_bblocks++;
6180         ebblock->real_offset = real_offset;
6181
6182         prev_args = cfg->args;
6183         prev_arg_types = cfg->arg_types;
6184         prev_inlined_method = cfg->inlined_method;
6185         cfg->inlined_method = cmethod;
6186         cfg->ret_var_set = FALSE;
6187         cfg->inline_depth ++;
6188         prev_real_offset = cfg->real_offset;
6189         prev_cbb_hash = cfg->cbb_hash;
6190         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6191         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6192         prev_cil_start = cfg->cil_start;
6193         prev_cbb = cfg->cbb;
6194         prev_current_method = cfg->current_method;
6195         prev_generic_context = cfg->generic_context;
6196         prev_ret_var_set = cfg->ret_var_set;
6197         prev_disable_inline = cfg->disable_inline;
6198
6199         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6200                 virtual = TRUE;
6201
6202         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6203
6204         ret_var_set = cfg->ret_var_set;
6205
6206         cfg->inlined_method = prev_inlined_method;
6207         cfg->real_offset = prev_real_offset;
6208         cfg->cbb_hash = prev_cbb_hash;
6209         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6210         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6211         cfg->cil_start = prev_cil_start;
6212         cfg->locals = prev_locals;
6213         cfg->args = prev_args;
6214         cfg->arg_types = prev_arg_types;
6215         cfg->current_method = prev_current_method;
6216         cfg->generic_context = prev_generic_context;
6217         cfg->ret_var_set = prev_ret_var_set;
6218         cfg->disable_inline = prev_disable_inline;
6219         cfg->inline_depth --;
6220
6221         if ((costs >= 0 && costs < 60) || inline_always) {
6222                 if (cfg->verbose_level > 2)
6223                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6224                 
6225                 cfg->stat_inlined_methods++;
6226
6227                 /* always add some code to avoid block split failures */
6228                 MONO_INST_NEW (cfg, ins, OP_NOP);
6229                 MONO_ADD_INS (prev_cbb, ins);
6230
6231                 prev_cbb->next_bb = sbblock;
6232                 link_bblock (cfg, prev_cbb, sbblock);
6233
6234                 /* 
6235                  * Get rid of the begin and end bblocks if possible to aid local
6236                  * optimizations.
6237                  */
6238                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6239
6240                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6241                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6242
6243                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6244                         MonoBasicBlock *prev = ebblock->in_bb [0];
6245                         mono_merge_basic_blocks (cfg, prev, ebblock);
6246                         cfg->cbb = prev;
6247                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6248                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6249                                 cfg->cbb = prev_cbb;
6250                         }
6251                 } else {
6252                         /* 
6253                          * Its possible that the rvar is set in some prev bblock, but not in others.
6254                          * (#1835).
6255                          */
6256                         if (rvar) {
6257                                 MonoBasicBlock *bb;
6258
6259                                 for (i = 0; i < ebblock->in_count; ++i) {
6260                                         bb = ebblock->in_bb [i];
6261
6262                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6263                                                 cfg->cbb = bb;
6264
6265                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6266                                         }
6267                                 }
6268                         }
6269
6270                         cfg->cbb = ebblock;
6271                 }
6272
6273                 *out_cbb = cfg->cbb;
6274
6275                 if (rvar) {
6276                         /*
6277                          * If the inlined method contains only a throw, then the ret var is not 
6278                          * set, so set it to a dummy value.
6279                          */
6280                         if (!ret_var_set)
6281                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6282
6283                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6284                         *sp++ = ins;
6285                 }
6286                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6287                 return costs + 1;
6288         } else {
6289                 if (cfg->verbose_level > 2)
6290                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6291                 cfg->exception_type = MONO_EXCEPTION_NONE;
6292                 mono_loader_clear_error ();
6293
6294                 /* This gets rid of the newly added bblocks */
6295                 cfg->cbb = prev_cbb;
6296         }
6297         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6298         return 0;
6299 }
6300
6301 /*
6302  * Some of these comments may well be out-of-date.
6303  * Design decisions: we do a single pass over the IL code (and we do bblock 
6304  * splitting/merging in the few cases when it's required: a back jump to an IL
6305  * address that was not already seen as bblock starting point).
6306  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6307  * Complex operations are decomposed in simpler ones right away. We need to let the 
6308  * arch-specific code peek and poke inside this process somehow (except when the 
6309  * optimizations can take advantage of the full semantic info of coarse opcodes).
6310  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6311  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6312  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6313  * opcode with value bigger than OP_LAST.
6314  * At this point the IR can be handed over to an interpreter, a dumb code generator
6315  * or to the optimizing code generator that will translate it to SSA form.
6316  *
6317  * Profiling directed optimizations.
6318  * We may compile by default with few or no optimizations and instrument the code
6319  * or the user may indicate what methods to optimize the most either in a config file
6320  * or through repeated runs where the compiler applies offline the optimizations to 
6321  * each method and then decides if it was worth it.
6322  */
6323
6324 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6325 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6326 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6327 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6328 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6329 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6330 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6331 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
6332
6333 /* offset from br.s -> br like opcodes */
6334 #define BIG_BRANCH_OFFSET 13
6335
6336 static gboolean
6337 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6338 {
6339         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6340
6341         return b == NULL || b == bb;
6342 }
6343
6344 static int
6345 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6346 {
6347         unsigned char *ip = start;
6348         unsigned char *target;
6349         int i;
6350         guint cli_addr;
6351         MonoBasicBlock *bblock;
6352         const MonoOpcode *opcode;
6353
6354         while (ip < end) {
6355                 cli_addr = ip - start;
6356                 i = mono_opcode_value ((const guint8 **)&ip, end);
6357                 if (i < 0)
6358                         UNVERIFIED;
6359                 opcode = &mono_opcodes [i];
6360                 switch (opcode->argument) {
6361                 case MonoInlineNone:
6362                         ip++; 
6363                         break;
6364                 case MonoInlineString:
6365                 case MonoInlineType:
6366                 case MonoInlineField:
6367                 case MonoInlineMethod:
6368                 case MonoInlineTok:
6369                 case MonoInlineSig:
6370                 case MonoShortInlineR:
6371                 case MonoInlineI:
6372                         ip += 5;
6373                         break;
6374                 case MonoInlineVar:
6375                         ip += 3;
6376                         break;
6377                 case MonoShortInlineVar:
6378                 case MonoShortInlineI:
6379                         ip += 2;
6380                         break;
6381                 case MonoShortInlineBrTarget:
6382                         target = start + cli_addr + 2 + (signed char)ip [1];
6383                         GET_BBLOCK (cfg, bblock, target);
6384                         ip += 2;
6385                         if (ip < end)
6386                                 GET_BBLOCK (cfg, bblock, ip);
6387                         break;
6388                 case MonoInlineBrTarget:
6389                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6390                         GET_BBLOCK (cfg, bblock, target);
6391                         ip += 5;
6392                         if (ip < end)
6393                                 GET_BBLOCK (cfg, bblock, ip);
6394                         break;
6395                 case MonoInlineSwitch: {
6396                         guint32 n = read32 (ip + 1);
6397                         guint32 j;
6398                         ip += 5;
6399                         cli_addr += 5 + 4 * n;
6400                         target = start + cli_addr;
6401                         GET_BBLOCK (cfg, bblock, target);
6402                         
6403                         for (j = 0; j < n; ++j) {
6404                                 target = start + cli_addr + (gint32)read32 (ip);
6405                                 GET_BBLOCK (cfg, bblock, target);
6406                                 ip += 4;
6407                         }
6408                         break;
6409                 }
6410                 case MonoInlineR:
6411                 case MonoInlineI8:
6412                         ip += 9;
6413                         break;
6414                 default:
6415                         g_assert_not_reached ();
6416                 }
6417
6418                 if (i == CEE_THROW) {
6419                         unsigned char *bb_start = ip - 1;
6420                         
6421                         /* Find the start of the bblock containing the throw */
6422                         bblock = NULL;
6423                         while ((bb_start >= start) && !bblock) {
6424                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6425                                 bb_start --;
6426                         }
6427                         if (bblock)
6428                                 bblock->out_of_line = 1;
6429                 }
6430         }
6431         return 0;
6432 unverified:
6433 exception_exit:
6434         *pos = ip;
6435         return 1;
6436 }
6437
6438 static inline MonoMethod *
6439 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6440 {
6441         MonoMethod *method;
6442
6443         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6444                 method = mono_method_get_wrapper_data (m, token);
6445                 if (context) {
6446                         MonoError error;
6447                         method = mono_class_inflate_generic_method_checked (method, context, &error);
6448                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
6449                 }
6450         } else {
6451                 method = mono_get_method_full (m->klass->image, token, klass, context);
6452         }
6453
6454         return method;
6455 }
6456
6457 static inline MonoMethod *
6458 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6459 {
6460         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6461
6462         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6463                 return NULL;
6464
6465         return method;
6466 }
6467
6468 static inline MonoClass*
6469 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6470 {
6471         MonoError error;
6472         MonoClass *klass;
6473
6474         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6475                 klass = mono_method_get_wrapper_data (method, token);
6476                 if (context)
6477                         klass = mono_class_inflate_generic_class (klass, context);
6478         } else {
6479                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6480                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6481         }
6482         if (klass)
6483                 mono_class_init (klass);
6484         return klass;
6485 }
6486
6487 static inline MonoMethodSignature*
6488 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6489 {
6490         MonoMethodSignature *fsig;
6491
6492         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6493                 MonoError error;
6494
6495                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6496                 if (context) {
6497                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6498                         // FIXME:
6499                         g_assert (mono_error_ok (&error));
6500                 }
6501         } else {
6502                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6503         }
6504         return fsig;
6505 }
6506
6507 /*
6508  * Returns TRUE if the JIT should abort inlining because "callee"
6509  * is influenced by security attributes.
6510  */
6511 static
6512 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6513 {
6514         guint32 result;
6515         
6516         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6517                 return TRUE;
6518         }
6519         
6520         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6521         if (result == MONO_JIT_SECURITY_OK)
6522                 return FALSE;
6523
6524         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6525                 /* Generate code to throw a SecurityException before the actual call/link */
6526                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6527                 MonoInst *args [2];
6528
6529                 NEW_ICONST (cfg, args [0], 4);
6530                 NEW_METHODCONST (cfg, args [1], caller);
6531                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6532         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6533                  /* don't hide previous results */
6534                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6535                 cfg->exception_data = result;
6536                 return TRUE;
6537         }
6538         
6539         return FALSE;
6540 }
6541
6542 static MonoMethod*
6543 throw_exception (void)
6544 {
6545         static MonoMethod *method = NULL;
6546
6547         if (!method) {
6548                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6549                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6550         }
6551         g_assert (method);
6552         return method;
6553 }
6554
6555 static void
6556 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6557 {
6558         MonoMethod *thrower = throw_exception ();
6559         MonoInst *args [1];
6560
6561         EMIT_NEW_PCONST (cfg, args [0], ex);
6562         mono_emit_method_call (cfg, thrower, args, NULL);
6563 }
6564
6565 /*
6566  * Return the original method is a wrapper is specified. We can only access 
6567  * the custom attributes from the original method.
6568  */
6569 static MonoMethod*
6570 get_original_method (MonoMethod *method)
6571 {
6572         if (method->wrapper_type == MONO_WRAPPER_NONE)
6573                 return method;
6574
6575         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6576         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6577                 return NULL;
6578
6579         /* in other cases we need to find the original method */
6580         return mono_marshal_method_from_wrapper (method);
6581 }
6582
6583 static void
6584 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6585                                           MonoBasicBlock *bblock, unsigned char *ip)
6586 {
6587         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6588         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6589         if (ex)
6590                 emit_throw_exception (cfg, ex);
6591 }
6592
6593 static void
6594 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6595                                          MonoBasicBlock *bblock, unsigned char *ip)
6596 {
6597         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6598         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6599         if (ex)
6600                 emit_throw_exception (cfg, ex);
6601 }
6602
6603 /*
6604  * Check that the IL instructions at ip are the array initialization
6605  * sequence and return the pointer to the data and the size.
6606  */
6607 static const char*
6608 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6609 {
6610         /*
6611          * newarr[System.Int32]
6612          * dup
6613          * ldtoken field valuetype ...
6614          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6615          */
6616         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6617                 MonoError error;
6618                 guint32 token = read32 (ip + 7);
6619                 guint32 field_token = read32 (ip + 2);
6620                 guint32 field_index = field_token & 0xffffff;
6621                 guint32 rva;
6622                 const char *data_ptr;
6623                 int size = 0;
6624                 MonoMethod *cmethod;
6625                 MonoClass *dummy_class;
6626                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6627                 int dummy_align;
6628
6629                 if (!field) {
6630                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6631                         return NULL;
6632                 }
6633
6634                 *out_field_token = field_token;
6635
6636                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6637                 if (!cmethod)
6638                         return NULL;
6639                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6640                         return NULL;
6641                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6642                 case MONO_TYPE_BOOLEAN:
6643                 case MONO_TYPE_I1:
6644                 case MONO_TYPE_U1:
6645                         size = 1; break;
6646                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6647 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6648                 case MONO_TYPE_CHAR:
6649                 case MONO_TYPE_I2:
6650                 case MONO_TYPE_U2:
6651                         size = 2; break;
6652                 case MONO_TYPE_I4:
6653                 case MONO_TYPE_U4:
6654                 case MONO_TYPE_R4:
6655                         size = 4; break;
6656                 case MONO_TYPE_R8:
6657                 case MONO_TYPE_I8:
6658                 case MONO_TYPE_U8:
6659                         size = 8; break;
6660 #endif
6661                 default:
6662                         return NULL;
6663                 }
6664                 size *= len;
6665                 if (size > mono_type_size (field->type, &dummy_align))
6666                     return NULL;
6667                 *out_size = size;
6668                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6669                 if (!image_is_dynamic (method->klass->image)) {
6670                         field_index = read32 (ip + 2) & 0xffffff;
6671                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6672                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6673                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6674                         /* for aot code we do the lookup on load */
6675                         if (aot && data_ptr)
6676                                 return GUINT_TO_POINTER (rva);
6677                 } else {
6678                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6679                         g_assert (!aot);
6680                         data_ptr = mono_field_get_data (field);
6681                 }
6682                 return data_ptr;
6683         }
6684         return NULL;
6685 }
6686
6687 static void
6688 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6689 {
6690         char *method_fname = mono_method_full_name (method, TRUE);
6691         char *method_code;
6692         MonoMethodHeader *header = mono_method_get_header (method);
6693
6694         if (header->code_size == 0)
6695                 method_code = g_strdup ("method body is empty.");
6696         else
6697                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6698         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6699         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6700         g_free (method_fname);
6701         g_free (method_code);
6702         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6703 }
6704
6705 static void
6706 set_exception_object (MonoCompile *cfg, MonoException *exception)
6707 {
6708         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6709         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6710         cfg->exception_ptr = exception;
6711 }
6712
6713 static void
6714 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6715 {
6716         MonoInst *ins;
6717         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6718         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6719                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6720                 /* Optimize reg-reg moves away */
6721                 /* 
6722                  * Can't optimize other opcodes, since sp[0] might point to
6723                  * the last ins of a decomposed opcode.
6724                  */
6725                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6726         } else {
6727                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6728         }
6729 }
6730
6731 /*
6732  * ldloca inhibits many optimizations so try to get rid of it in common
6733  * cases.
6734  */
6735 static inline unsigned char *
6736 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6737 {
6738         int local, token;
6739         MonoClass *klass;
6740         MonoType *type;
6741
6742         if (size == 1) {
6743                 local = ip [1];
6744                 ip += 2;
6745         } else {
6746                 local = read16 (ip + 2);
6747                 ip += 4;
6748         }
6749         
6750         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6751                 /* From the INITOBJ case */
6752                 token = read32 (ip + 2);
6753                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6754                 CHECK_TYPELOAD (klass);
6755                 type = mini_replace_type (&klass->byval_arg);
6756                 emit_init_local (cfg, local, type, TRUE);
6757                 return ip + 6;
6758         }
6759  exception_exit:
6760         return NULL;
6761 }
6762
6763 static gboolean
6764 is_exception_class (MonoClass *class)
6765 {
6766         while (class) {
6767                 if (class == mono_defaults.exception_class)
6768                         return TRUE;
6769                 class = class->parent;
6770         }
6771         return FALSE;
6772 }
6773
6774 /*
6775  * is_jit_optimizer_disabled:
6776  *
6777  *   Determine whenever M's assembly has a DebuggableAttribute with the
6778  * IsJITOptimizerDisabled flag set.
6779  */
6780 static gboolean
6781 is_jit_optimizer_disabled (MonoMethod *m)
6782 {
6783         MonoAssembly *ass = m->klass->image->assembly;
6784         MonoCustomAttrInfo* attrs;
6785         static MonoClass *klass;
6786         int i;
6787         gboolean val = FALSE;
6788
6789         g_assert (ass);
6790         if (ass->jit_optimizer_disabled_inited)
6791                 return ass->jit_optimizer_disabled;
6792
6793         if (!klass)
6794                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6795         if (!klass) {
6796                 /* Linked away */
6797                 ass->jit_optimizer_disabled = FALSE;
6798                 mono_memory_barrier ();
6799                 ass->jit_optimizer_disabled_inited = TRUE;
6800                 return FALSE;
6801         }
6802
6803         attrs = mono_custom_attrs_from_assembly (ass);
6804         if (attrs) {
6805                 for (i = 0; i < attrs->num_attrs; ++i) {
6806                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6807                         const gchar *p;
6808                         int len;
6809                         MonoMethodSignature *sig;
6810
6811                         if (!attr->ctor || attr->ctor->klass != klass)
6812                                 continue;
6813                         /* Decode the attribute. See reflection.c */
6814                         len = attr->data_size;
6815                         p = (const char*)attr->data;
6816                         g_assert (read16 (p) == 0x0001);
6817                         p += 2;
6818
6819                         // FIXME: Support named parameters
6820                         sig = mono_method_signature (attr->ctor);
6821                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6822                                 continue;
6823                         /* Two boolean arguments */
6824                         p ++;
6825                         val = *p;
6826                 }
6827                 mono_custom_attrs_free (attrs);
6828         }
6829
6830         ass->jit_optimizer_disabled = val;
6831         mono_memory_barrier ();
6832         ass->jit_optimizer_disabled_inited = TRUE;
6833
6834         return val;
6835 }
6836
6837 static gboolean
6838 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
6839 {
6840         gboolean supported_tail_call;
6841         int i;
6842
6843 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
6844         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
6845 #else
6846         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6847 #endif
6848
6849         for (i = 0; i < fsig->param_count; ++i) {
6850                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6851                         /* These can point to the current method's stack */
6852                         supported_tail_call = FALSE;
6853         }
6854         if (fsig->hasthis && cmethod->klass->valuetype)
6855                 /* this might point to the current method's stack */
6856                 supported_tail_call = FALSE;
6857         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6858                 supported_tail_call = FALSE;
6859         if (cfg->method->save_lmf)
6860                 supported_tail_call = FALSE;
6861         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6862                 supported_tail_call = FALSE;
6863         if (call_opcode != CEE_CALL)
6864                 supported_tail_call = FALSE;
6865
6866         /* Debugging support */
6867 #if 0
6868         if (supported_tail_call) {
6869                 if (!mono_debug_count ())
6870                         supported_tail_call = FALSE;
6871         }
6872 #endif
6873
6874         return supported_tail_call;
6875 }
6876
6877 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6878  * it to the thread local value based on the tls_offset field. Every other kind of access to
6879  * the field causes an assert.
6880  */
6881 static gboolean
6882 is_magic_tls_access (MonoClassField *field)
6883 {
6884         if (strcmp (field->name, "tlsdata"))
6885                 return FALSE;
6886         if (strcmp (field->parent->name, "ThreadLocal`1"))
6887                 return FALSE;
6888         return field->parent->image == mono_defaults.corlib;
6889 }
6890
6891 /* emits the code needed to access a managed tls var (like ThreadStatic)
6892  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6893  * pointer for the current thread.
6894  * Returns the MonoInst* representing the address of the tls var.
6895  */
6896 static MonoInst*
6897 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6898 {
6899         MonoInst *addr;
6900         int static_data_reg, array_reg, dreg;
6901         int offset2_reg, idx_reg;
6902         // inlined access to the tls data
6903         // idx = (offset >> 24) - 1;
6904         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6905         static_data_reg = alloc_ireg (cfg);
6906         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
6907         idx_reg = alloc_ireg (cfg);
6908         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6909         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6910         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6911         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6912         array_reg = alloc_ireg (cfg);
6913         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6914         offset2_reg = alloc_ireg (cfg);
6915         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6916         dreg = alloc_ireg (cfg);
6917         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6918         return addr;
6919 }
6920
6921 /*
6922  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6923  * this address is cached per-method in cached_tls_addr.
6924  */
6925 static MonoInst*
6926 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6927 {
6928         MonoInst *load, *addr, *temp, *store, *thread_ins;
6929         MonoClassField *offset_field;
6930
6931         if (*cached_tls_addr) {
6932                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6933                 return addr;
6934         }
6935         thread_ins = mono_get_thread_intrinsic (cfg);
6936         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6937
6938         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6939         if (thread_ins) {
6940                 MONO_ADD_INS (cfg->cbb, thread_ins);
6941         } else {
6942                 MonoMethod *thread_method;
6943                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6944                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6945         }
6946         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6947         addr->klass = mono_class_from_mono_type (tls_field->type);
6948         addr->type = STACK_MP;
6949         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6950         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6951
6952         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6953         return addr;
6954 }
6955
6956 /*
6957  * handle_ctor_call:
6958  *
6959  *   Handle calls made to ctors from NEWOBJ opcodes.
6960  *
6961  *   REF_BBLOCK will point to the current bblock after the call.
6962  */
6963 static void
6964 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
6965                                   MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
6966 {
6967         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
6968         MonoBasicBlock *bblock = *ref_bblock;
6969
6970         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
6971                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
6972                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
6973                         mono_class_vtable (cfg->domain, cmethod->klass);
6974                         CHECK_TYPELOAD (cmethod->klass);
6975
6976                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
6977                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
6978                 } else {
6979                         if (context_used) {
6980                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
6981                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
6982                         } else {
6983                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6984
6985                                 CHECK_TYPELOAD (cmethod->klass);
6986                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
6987                         }
6988                 }
6989         }
6990
6991         /* Avoid virtual calls to ctors if possible */
6992         if (mono_class_is_marshalbyref (cmethod->klass))
6993                 callvirt_this_arg = sp [0];
6994
6995         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
6996                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
6997                 CHECK_CFG_EXCEPTION;
6998         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
6999                            mono_method_check_inlining (cfg, cmethod) &&
7000                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7001                 int costs;
7002
7003                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
7004                         cfg->real_offset += 5;
7005
7006                         *inline_costs += costs - 5;
7007                         *ref_bblock = bblock;
7008                 } else {
7009                         INLINE_FAILURE ("inline failure");
7010                         // FIXME-VT: Clean this up
7011                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7012                                 GSHAREDVT_FAILURE(*ip);
7013                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7014                 }
7015         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
7016                 MonoInst *addr;
7017
7018                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7019                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7020         } else if (context_used &&
7021                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7022                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7023                 MonoInst *cmethod_addr;
7024
7025                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7026
7027                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7028                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7029
7030                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7031         } else {
7032                 INLINE_FAILURE ("ctor call");
7033                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7034                                                                                   callvirt_this_arg, NULL, vtable_arg);
7035         }
7036  exception_exit:
7037         return;
7038 }
7039
7040 /*
7041  * mono_method_to_ir:
7042  *
7043  *   Translate the .net IL into linear IR.
7044  */
7045 int
7046 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7047                    MonoInst *return_var, MonoInst **inline_args, 
7048                    guint inline_offset, gboolean is_virtual_call)
7049 {
7050         MonoError error;
7051         MonoInst *ins, **sp, **stack_start;
7052         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
7053         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7054         MonoMethod *cmethod, *method_definition;
7055         MonoInst **arg_array;
7056         MonoMethodHeader *header;
7057         MonoImage *image;
7058         guint32 token, ins_flag;
7059         MonoClass *klass;
7060         MonoClass *constrained_call = NULL;
7061         unsigned char *ip, *end, *target, *err_pos;
7062         MonoMethodSignature *sig;
7063         MonoGenericContext *generic_context = NULL;
7064         MonoGenericContainer *generic_container = NULL;
7065         MonoType **param_types;
7066         int i, n, start_new_bblock, dreg;
7067         int num_calls = 0, inline_costs = 0;
7068         int breakpoint_id = 0;
7069         guint num_args;
7070         MonoBoolean security, pinvoke;
7071         MonoSecurityManager* secman = NULL;
7072         MonoDeclSecurityActions actions;
7073         GSList *class_inits = NULL;
7074         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7075         int context_used;
7076         gboolean init_locals, seq_points, skip_dead_blocks;
7077         gboolean sym_seq_points = FALSE;
7078         MonoInst *cached_tls_addr = NULL;
7079         MonoDebugMethodInfo *minfo;
7080         MonoBitSet *seq_point_locs = NULL;
7081         MonoBitSet *seq_point_set_locs = NULL;
7082
7083         cfg->disable_inline = is_jit_optimizer_disabled (method);
7084
7085         /* serialization and xdomain stuff may need access to private fields and methods */
7086         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7087         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7088         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7089         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7090         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7091         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7092
7093         dont_verify |= mono_security_smcs_hack_enabled ();
7094
7095         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7096         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7097         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7098         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7099         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7100
7101         image = method->klass->image;
7102         header = mono_method_get_header (method);
7103         if (!header) {
7104                 MonoLoaderError *error;
7105
7106                 if ((error = mono_loader_get_last_error ())) {
7107                         mono_cfg_set_exception (cfg, error->exception_type);
7108                 } else {
7109                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7110                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7111                 }
7112                 goto exception_exit;
7113         }
7114         generic_container = mono_method_get_generic_container (method);
7115         sig = mono_method_signature (method);
7116         num_args = sig->hasthis + sig->param_count;
7117         ip = (unsigned char*)header->code;
7118         cfg->cil_start = ip;
7119         end = ip + header->code_size;
7120         cfg->stat_cil_code_size += header->code_size;
7121
7122         seq_points = cfg->gen_seq_points && cfg->method == method;
7123 #ifdef PLATFORM_ANDROID
7124         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
7125 #endif
7126
7127         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7128                 /* We could hit a seq point before attaching to the JIT (#8338) */
7129                 seq_points = FALSE;
7130         }
7131
7132         if (cfg->gen_seq_points_debug_data && cfg->method == method) {
7133                 minfo = mono_debug_lookup_method (method);
7134                 if (minfo) {
7135                         int i, n_il_offsets;
7136                         int *il_offsets;
7137                         int *line_numbers;
7138
7139                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
7140                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7141                         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);
7142                         sym_seq_points = TRUE;
7143                         for (i = 0; i < n_il_offsets; ++i) {
7144                                 if (il_offsets [i] < header->code_size)
7145                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
7146                         }
7147                         g_free (il_offsets);
7148                         g_free (line_numbers);
7149                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7150                         /* Methods without line number info like auto-generated property accessors */
7151                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7152                         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);
7153                         sym_seq_points = TRUE;
7154                 }
7155         }
7156
7157         /* 
7158          * Methods without init_locals set could cause asserts in various passes
7159          * (#497220). To work around this, we emit dummy initialization opcodes
7160          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7161          * on some platforms.
7162          */
7163         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7164                 init_locals = header->init_locals;
7165         else
7166                 init_locals = TRUE;
7167
7168         method_definition = method;
7169         while (method_definition->is_inflated) {
7170                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7171                 method_definition = imethod->declaring;
7172         }
7173
7174         /* SkipVerification is not allowed if core-clr is enabled */
7175         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7176                 dont_verify = TRUE;
7177                 dont_verify_stloc = TRUE;
7178         }
7179
7180         if (sig->is_inflated)
7181                 generic_context = mono_method_get_context (method);
7182         else if (generic_container)
7183                 generic_context = &generic_container->context;
7184         cfg->generic_context = generic_context;
7185
7186         if (!cfg->generic_sharing_context)
7187                 g_assert (!sig->has_type_parameters);
7188
7189         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7190                 g_assert (method->is_inflated);
7191                 g_assert (mono_method_get_context (method)->method_inst);
7192         }
7193         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7194                 g_assert (sig->generic_param_count);
7195
7196         if (cfg->method == method) {
7197                 cfg->real_offset = 0;
7198         } else {
7199                 cfg->real_offset = inline_offset;
7200         }
7201
7202         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7203         cfg->cil_offset_to_bb_len = header->code_size;
7204
7205         cfg->current_method = method;
7206
7207         if (cfg->verbose_level > 2)
7208                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7209
7210         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7211         if (sig->hasthis)
7212                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7213         for (n = 0; n < sig->param_count; ++n)
7214                 param_types [n + sig->hasthis] = sig->params [n];
7215         cfg->arg_types = param_types;
7216
7217         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7218         if (cfg->method == method) {
7219
7220                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7221                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7222
7223                 /* ENTRY BLOCK */
7224                 NEW_BBLOCK (cfg, start_bblock);
7225                 cfg->bb_entry = start_bblock;
7226                 start_bblock->cil_code = NULL;
7227                 start_bblock->cil_length = 0;
7228 #if defined(__native_client_codegen__)
7229                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
7230                 ins->dreg = alloc_dreg (cfg, STACK_I4);
7231                 MONO_ADD_INS (start_bblock, ins);
7232 #endif
7233
7234                 /* EXIT BLOCK */
7235                 NEW_BBLOCK (cfg, end_bblock);
7236                 cfg->bb_exit = end_bblock;
7237                 end_bblock->cil_code = NULL;
7238                 end_bblock->cil_length = 0;
7239                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7240                 g_assert (cfg->num_bblocks == 2);
7241
7242                 arg_array = cfg->args;
7243
7244                 if (header->num_clauses) {
7245                         cfg->spvars = g_hash_table_new (NULL, NULL);
7246                         cfg->exvars = g_hash_table_new (NULL, NULL);
7247                 }
7248                 /* handle exception clauses */
7249                 for (i = 0; i < header->num_clauses; ++i) {
7250                         MonoBasicBlock *try_bb;
7251                         MonoExceptionClause *clause = &header->clauses [i];
7252                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7253                         try_bb->real_offset = clause->try_offset;
7254                         try_bb->try_start = TRUE;
7255                         try_bb->region = ((i + 1) << 8) | clause->flags;
7256                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7257                         tblock->real_offset = clause->handler_offset;
7258                         tblock->flags |= BB_EXCEPTION_HANDLER;
7259
7260                         /*
7261                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7262                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7263                          */
7264                         if (COMPILE_LLVM (cfg))
7265                                 link_bblock (cfg, try_bb, tblock);
7266
7267                         if (*(ip + clause->handler_offset) == CEE_POP)
7268                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7269
7270                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7271                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7272                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7273                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7274                                 MONO_ADD_INS (tblock, ins);
7275
7276                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7277                                         /* finally clauses already have a seq point */
7278                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7279                                         MONO_ADD_INS (tblock, ins);
7280                                 }
7281
7282                                 /* todo: is a fault block unsafe to optimize? */
7283                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7284                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7285                         }
7286
7287
7288                         /*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);
7289                           while (p < end) {
7290                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7291                           }*/
7292                         /* catch and filter blocks get the exception object on the stack */
7293                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7294                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7295                                 MonoInst *dummy_use;
7296
7297                                 /* mostly like handle_stack_args (), but just sets the input args */
7298                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7299                                 tblock->in_scount = 1;
7300                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7301                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7302
7303                                 /* 
7304                                  * Add a dummy use for the exvar so its liveness info will be
7305                                  * correct.
7306                                  */
7307                                 cfg->cbb = tblock;
7308                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7309                                 
7310                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7311                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7312                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7313                                         tblock->real_offset = clause->data.filter_offset;
7314                                         tblock->in_scount = 1;
7315                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7316                                         /* The filter block shares the exvar with the handler block */
7317                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7318                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7319                                         MONO_ADD_INS (tblock, ins);
7320                                 }
7321                         }
7322
7323                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7324                                         clause->data.catch_class &&
7325                                         cfg->generic_sharing_context &&
7326                                         mono_class_check_context_used (clause->data.catch_class)) {
7327                                 /*
7328                                  * In shared generic code with catch
7329                                  * clauses containing type variables
7330                                  * the exception handling code has to
7331                                  * be able to get to the rgctx.
7332                                  * Therefore we have to make sure that
7333                                  * the vtable/mrgctx argument (for
7334                                  * static or generic methods) or the
7335                                  * "this" argument (for non-static
7336                                  * methods) are live.
7337                                  */
7338                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7339                                                 mini_method_get_context (method)->method_inst ||
7340                                                 method->klass->valuetype) {
7341                                         mono_get_vtable_var (cfg);
7342                                 } else {
7343                                         MonoInst *dummy_use;
7344
7345                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7346                                 }
7347                         }
7348                 }
7349         } else {
7350                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7351                 cfg->cbb = start_bblock;
7352                 cfg->args = arg_array;
7353                 mono_save_args (cfg, sig, inline_args);
7354         }
7355
7356         /* FIRST CODE BLOCK */
7357         NEW_BBLOCK (cfg, bblock);
7358         bblock->cil_code = ip;
7359         cfg->cbb = bblock;
7360         cfg->ip = ip;
7361
7362         ADD_BBLOCK (cfg, bblock);
7363
7364         if (cfg->method == method) {
7365                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7366                 if (breakpoint_id) {
7367                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7368                         MONO_ADD_INS (bblock, ins);
7369                 }
7370         }
7371
7372         if (mono_security_cas_enabled ())
7373                 secman = mono_security_manager_get_methods ();
7374
7375         security = (secman && mono_security_method_has_declsec (method));
7376         /* at this point having security doesn't mean we have any code to generate */
7377         if (security && (cfg->method == method)) {
7378                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
7379                  * And we do not want to enter the next section (with allocation) if we
7380                  * have nothing to generate */
7381                 security = mono_declsec_get_demands (method, &actions);
7382         }
7383
7384         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
7385         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
7386         if (pinvoke) {
7387                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7388                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7389                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
7390
7391                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
7392                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7393                                 pinvoke = FALSE;
7394                         }
7395                         if (custom)
7396                                 mono_custom_attrs_free (custom);
7397
7398                         if (pinvoke) {
7399                                 custom = mono_custom_attrs_from_class (wrapped->klass);
7400                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7401                                         pinvoke = FALSE;
7402                                 }
7403                                 if (custom)
7404                                         mono_custom_attrs_free (custom);
7405                         }
7406                 } else {
7407                         /* not a P/Invoke after all */
7408                         pinvoke = FALSE;
7409                 }
7410         }
7411         
7412         /* we use a separate basic block for the initialization code */
7413         NEW_BBLOCK (cfg, init_localsbb);
7414         cfg->bb_init = init_localsbb;
7415         init_localsbb->real_offset = cfg->real_offset;
7416         start_bblock->next_bb = init_localsbb;
7417         init_localsbb->next_bb = bblock;
7418         link_bblock (cfg, start_bblock, init_localsbb);
7419         link_bblock (cfg, init_localsbb, bblock);
7420                 
7421         cfg->cbb = init_localsbb;
7422
7423         if (cfg->gsharedvt && cfg->method == method) {
7424                 MonoGSharedVtMethodInfo *info;
7425                 MonoInst *var, *locals_var;
7426                 int dreg;
7427
7428                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7429                 info->method = cfg->method;
7430                 info->count_entries = 16;
7431                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7432                 cfg->gsharedvt_info = info;
7433
7434                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7435                 /* prevent it from being register allocated */
7436                 //var->flags |= MONO_INST_VOLATILE;
7437                 cfg->gsharedvt_info_var = var;
7438
7439                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7440                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7441
7442                 /* Allocate locals */
7443                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7444                 /* prevent it from being register allocated */
7445                 //locals_var->flags |= MONO_INST_VOLATILE;
7446                 cfg->gsharedvt_locals_var = locals_var;
7447
7448                 dreg = alloc_ireg (cfg);
7449                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7450
7451                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7452                 ins->dreg = locals_var->dreg;
7453                 ins->sreg1 = dreg;
7454                 MONO_ADD_INS (cfg->cbb, ins);
7455                 cfg->gsharedvt_locals_var_ins = ins;
7456                 
7457                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7458                 /*
7459                 if (init_locals)
7460                         ins->flags |= MONO_INST_INIT;
7461                 */
7462         }
7463
7464         /* at this point we know, if security is TRUE, that some code needs to be generated */
7465         if (security && (cfg->method == method)) {
7466                 MonoInst *args [2];
7467
7468                 cfg->stat_cas_demand_generation++;
7469
7470                 if (actions.demand.blob) {
7471                         /* Add code for SecurityAction.Demand */
7472                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
7473                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
7474                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7475                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7476                 }
7477                 if (actions.noncasdemand.blob) {
7478                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7479                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7480                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7481                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7482                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7483                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7484                 }
7485                 if (actions.demandchoice.blob) {
7486                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7487                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7488                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7489                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7490                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7491                 }
7492         }
7493
7494         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7495         if (pinvoke) {
7496                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7497         }
7498
7499         if (mono_security_core_clr_enabled ()) {
7500                 /* check if this is native code, e.g. an icall or a p/invoke */
7501                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7502                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7503                         if (wrapped) {
7504                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7505                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7506
7507                                 /* if this ia a native call then it can only be JITted from platform code */
7508                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7509                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7510                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7511                                                         mono_get_exception_method_access ();
7512                                                 emit_throw_exception (cfg, ex);
7513                                         }
7514                                 }
7515                         }
7516                 }
7517         }
7518
7519         CHECK_CFG_EXCEPTION;
7520
7521         if (header->code_size == 0)
7522                 UNVERIFIED;
7523
7524         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7525                 ip = err_pos;
7526                 UNVERIFIED;
7527         }
7528
7529         if (cfg->method == method)
7530                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7531
7532         for (n = 0; n < header->num_locals; ++n) {
7533                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7534                         UNVERIFIED;
7535         }
7536         class_inits = NULL;
7537
7538         /* We force the vtable variable here for all shared methods
7539            for the possibility that they might show up in a stack
7540            trace where their exact instantiation is needed. */
7541         if (cfg->generic_sharing_context && method == cfg->method) {
7542                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7543                                 mini_method_get_context (method)->method_inst ||
7544                                 method->klass->valuetype) {
7545                         mono_get_vtable_var (cfg);
7546                 } else {
7547                         /* FIXME: Is there a better way to do this?
7548                            We need the variable live for the duration
7549                            of the whole method. */
7550                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7551                 }
7552         }
7553
7554         /* add a check for this != NULL to inlined methods */
7555         if (is_virtual_call) {
7556                 MonoInst *arg_ins;
7557
7558                 NEW_ARGLOAD (cfg, arg_ins, 0);
7559                 MONO_ADD_INS (cfg->cbb, arg_ins);
7560                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7561         }
7562
7563         skip_dead_blocks = !dont_verify;
7564         if (skip_dead_blocks) {
7565                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
7566                 CHECK_CFG_ERROR;
7567                 g_assert (bb);
7568         }
7569
7570         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7571         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7572
7573         ins_flag = 0;
7574         start_new_bblock = 0;
7575         cfg->cbb = bblock;
7576         while (ip < end) {
7577                 if (cfg->method == method)
7578                         cfg->real_offset = ip - header->code;
7579                 else
7580                         cfg->real_offset = inline_offset;
7581                 cfg->ip = ip;
7582
7583                 context_used = 0;
7584                 
7585                 if (start_new_bblock) {
7586                         bblock->cil_length = ip - bblock->cil_code;
7587                         if (start_new_bblock == 2) {
7588                                 g_assert (ip == tblock->cil_code);
7589                         } else {
7590                                 GET_BBLOCK (cfg, tblock, ip);
7591                         }
7592                         bblock->next_bb = tblock;
7593                         bblock = tblock;
7594                         cfg->cbb = bblock;
7595                         start_new_bblock = 0;
7596                         for (i = 0; i < bblock->in_scount; ++i) {
7597                                 if (cfg->verbose_level > 3)
7598                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7599                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7600                                 *sp++ = ins;
7601                         }
7602                         if (class_inits)
7603                                 g_slist_free (class_inits);
7604                         class_inits = NULL;
7605                 } else {
7606                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7607                                 link_bblock (cfg, bblock, tblock);
7608                                 if (sp != stack_start) {
7609                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7610                                         sp = stack_start;
7611                                         CHECK_UNVERIFIABLE (cfg);
7612                                 }
7613                                 bblock->next_bb = tblock;
7614                                 bblock = tblock;
7615                                 cfg->cbb = bblock;
7616                                 for (i = 0; i < bblock->in_scount; ++i) {
7617                                         if (cfg->verbose_level > 3)
7618                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7619                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7620                                         *sp++ = ins;
7621                                 }
7622                                 g_slist_free (class_inits);
7623                                 class_inits = NULL;
7624                         }
7625                 }
7626
7627                 if (skip_dead_blocks) {
7628                         int ip_offset = ip - header->code;
7629
7630                         if (ip_offset == bb->end)
7631                                 bb = bb->next;
7632
7633                         if (bb->dead) {
7634                                 int op_size = mono_opcode_size (ip, end);
7635                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7636
7637                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7638
7639                                 if (ip_offset + op_size == bb->end) {
7640                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7641                                         MONO_ADD_INS (bblock, ins);
7642                                         start_new_bblock = 1;
7643                                 }
7644
7645                                 ip += op_size;
7646                                 continue;
7647                         }
7648                 }
7649                 /*
7650                  * Sequence points are points where the debugger can place a breakpoint.
7651                  * Currently, we generate these automatically at points where the IL
7652                  * stack is empty.
7653                  */
7654                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7655                         /*
7656                          * Make methods interruptable at the beginning, and at the targets of
7657                          * backward branches.
7658                          * Also, do this at the start of every bblock in methods with clauses too,
7659                          * to be able to handle instructions with inprecise control flow like
7660                          * throw/endfinally.
7661                          * Backward branches are handled at the end of method-to-ir ().
7662                          */
7663                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7664
7665                         /* Avoid sequence points on empty IL like .volatile */
7666                         // FIXME: Enable this
7667                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7668                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7669                         if (sp != stack_start)
7670                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7671                         MONO_ADD_INS (cfg->cbb, ins);
7672
7673                         if (sym_seq_points)
7674                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7675                 }
7676
7677                 bblock->real_offset = cfg->real_offset;
7678
7679                 if ((cfg->method == method) && cfg->coverage_info) {
7680                         guint32 cil_offset = ip - header->code;
7681                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7682
7683                         /* TODO: Use an increment here */
7684 #if defined(TARGET_X86)
7685                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7686                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7687                         ins->inst_imm = 1;
7688                         MONO_ADD_INS (cfg->cbb, ins);
7689 #else
7690                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7691                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7692 #endif
7693                 }
7694
7695                 if (cfg->verbose_level > 3)
7696                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7697
7698                 switch (*ip) {
7699                 case CEE_NOP:
7700                         if (seq_points && !sym_seq_points && sp != stack_start) {
7701                                 /*
7702                                  * The C# compiler uses these nops to notify the JIT that it should
7703                                  * insert seq points.
7704                                  */
7705                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7706                                 MONO_ADD_INS (cfg->cbb, ins);
7707                         }
7708                         if (cfg->keep_cil_nops)
7709                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7710                         else
7711                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7712                         ip++;
7713                         MONO_ADD_INS (bblock, ins);
7714                         break;
7715                 case CEE_BREAK:
7716                         if (should_insert_brekpoint (cfg->method)) {
7717                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7718                         } else {
7719                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7720                         }
7721                         ip++;
7722                         MONO_ADD_INS (bblock, ins);
7723                         break;
7724                 case CEE_LDARG_0:
7725                 case CEE_LDARG_1:
7726                 case CEE_LDARG_2:
7727                 case CEE_LDARG_3:
7728                         CHECK_STACK_OVF (1);
7729                         n = (*ip)-CEE_LDARG_0;
7730                         CHECK_ARG (n);
7731                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7732                         ip++;
7733                         *sp++ = ins;
7734                         break;
7735                 case CEE_LDLOC_0:
7736                 case CEE_LDLOC_1:
7737                 case CEE_LDLOC_2:
7738                 case CEE_LDLOC_3:
7739                         CHECK_STACK_OVF (1);
7740                         n = (*ip)-CEE_LDLOC_0;
7741                         CHECK_LOCAL (n);
7742                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7743                         ip++;
7744                         *sp++ = ins;
7745                         break;
7746                 case CEE_STLOC_0:
7747                 case CEE_STLOC_1:
7748                 case CEE_STLOC_2:
7749                 case CEE_STLOC_3: {
7750                         CHECK_STACK (1);
7751                         n = (*ip)-CEE_STLOC_0;
7752                         CHECK_LOCAL (n);
7753                         --sp;
7754                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7755                                 UNVERIFIED;
7756                         emit_stloc_ir (cfg, sp, header, n);
7757                         ++ip;
7758                         inline_costs += 1;
7759                         break;
7760                         }
7761                 case CEE_LDARG_S:
7762                         CHECK_OPSIZE (2);
7763                         CHECK_STACK_OVF (1);
7764                         n = ip [1];
7765                         CHECK_ARG (n);
7766                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7767                         *sp++ = ins;
7768                         ip += 2;
7769                         break;
7770                 case CEE_LDARGA_S:
7771                         CHECK_OPSIZE (2);
7772                         CHECK_STACK_OVF (1);
7773                         n = ip [1];
7774                         CHECK_ARG (n);
7775                         NEW_ARGLOADA (cfg, ins, n);
7776                         MONO_ADD_INS (cfg->cbb, ins);
7777                         *sp++ = ins;
7778                         ip += 2;
7779                         break;
7780                 case CEE_STARG_S:
7781                         CHECK_OPSIZE (2);
7782                         CHECK_STACK (1);
7783                         --sp;
7784                         n = ip [1];
7785                         CHECK_ARG (n);
7786                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7787                                 UNVERIFIED;
7788                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7789                         ip += 2;
7790                         break;
7791                 case CEE_LDLOC_S:
7792                         CHECK_OPSIZE (2);
7793                         CHECK_STACK_OVF (1);
7794                         n = ip [1];
7795                         CHECK_LOCAL (n);
7796                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7797                         *sp++ = ins;
7798                         ip += 2;
7799                         break;
7800                 case CEE_LDLOCA_S: {
7801                         unsigned char *tmp_ip;
7802                         CHECK_OPSIZE (2);
7803                         CHECK_STACK_OVF (1);
7804                         CHECK_LOCAL (ip [1]);
7805
7806                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7807                                 ip = tmp_ip;
7808                                 inline_costs += 1;
7809                                 break;
7810                         }
7811
7812                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7813                         *sp++ = ins;
7814                         ip += 2;
7815                         break;
7816                 }
7817                 case CEE_STLOC_S:
7818                         CHECK_OPSIZE (2);
7819                         CHECK_STACK (1);
7820                         --sp;
7821                         CHECK_LOCAL (ip [1]);
7822                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7823                                 UNVERIFIED;
7824                         emit_stloc_ir (cfg, sp, header, ip [1]);
7825                         ip += 2;
7826                         inline_costs += 1;
7827                         break;
7828                 case CEE_LDNULL:
7829                         CHECK_STACK_OVF (1);
7830                         EMIT_NEW_PCONST (cfg, ins, NULL);
7831                         ins->type = STACK_OBJ;
7832                         ++ip;
7833                         *sp++ = ins;
7834                         break;
7835                 case CEE_LDC_I4_M1:
7836                         CHECK_STACK_OVF (1);
7837                         EMIT_NEW_ICONST (cfg, ins, -1);
7838                         ++ip;
7839                         *sp++ = ins;
7840                         break;
7841                 case CEE_LDC_I4_0:
7842                 case CEE_LDC_I4_1:
7843                 case CEE_LDC_I4_2:
7844                 case CEE_LDC_I4_3:
7845                 case CEE_LDC_I4_4:
7846                 case CEE_LDC_I4_5:
7847                 case CEE_LDC_I4_6:
7848                 case CEE_LDC_I4_7:
7849                 case CEE_LDC_I4_8:
7850                         CHECK_STACK_OVF (1);
7851                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7852                         ++ip;
7853                         *sp++ = ins;
7854                         break;
7855                 case CEE_LDC_I4_S:
7856                         CHECK_OPSIZE (2);
7857                         CHECK_STACK_OVF (1);
7858                         ++ip;
7859                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7860                         ++ip;
7861                         *sp++ = ins;
7862                         break;
7863                 case CEE_LDC_I4:
7864                         CHECK_OPSIZE (5);
7865                         CHECK_STACK_OVF (1);
7866                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7867                         ip += 5;
7868                         *sp++ = ins;
7869                         break;
7870                 case CEE_LDC_I8:
7871                         CHECK_OPSIZE (9);
7872                         CHECK_STACK_OVF (1);
7873                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7874                         ins->type = STACK_I8;
7875                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7876                         ++ip;
7877                         ins->inst_l = (gint64)read64 (ip);
7878                         MONO_ADD_INS (bblock, ins);
7879                         ip += 8;
7880                         *sp++ = ins;
7881                         break;
7882                 case CEE_LDC_R4: {
7883                         float *f;
7884                         gboolean use_aotconst = FALSE;
7885
7886 #ifdef TARGET_POWERPC
7887                         /* FIXME: Clean this up */
7888                         if (cfg->compile_aot)
7889                                 use_aotconst = TRUE;
7890 #endif
7891
7892                         /* FIXME: we should really allocate this only late in the compilation process */
7893                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7894                         CHECK_OPSIZE (5);
7895                         CHECK_STACK_OVF (1);
7896
7897                         if (use_aotconst) {
7898                                 MonoInst *cons;
7899                                 int dreg;
7900
7901                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7902
7903                                 dreg = alloc_freg (cfg);
7904                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7905                                 ins->type = STACK_R8;
7906                         } else {
7907                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7908                                 ins->type = STACK_R8;
7909                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7910                                 ins->inst_p0 = f;
7911                                 MONO_ADD_INS (bblock, ins);
7912                         }
7913                         ++ip;
7914                         readr4 (ip, f);
7915                         ip += 4;
7916                         *sp++ = ins;                    
7917                         break;
7918                 }
7919                 case CEE_LDC_R8: {
7920                         double *d;
7921                         gboolean use_aotconst = FALSE;
7922
7923 #ifdef TARGET_POWERPC
7924                         /* FIXME: Clean this up */
7925                         if (cfg->compile_aot)
7926                                 use_aotconst = TRUE;
7927 #endif
7928
7929                         /* FIXME: we should really allocate this only late in the compilation process */
7930                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7931                         CHECK_OPSIZE (9);
7932                         CHECK_STACK_OVF (1);
7933
7934                         if (use_aotconst) {
7935                                 MonoInst *cons;
7936                                 int dreg;
7937
7938                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7939
7940                                 dreg = alloc_freg (cfg);
7941                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7942                                 ins->type = STACK_R8;
7943                         } else {
7944                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7945                                 ins->type = STACK_R8;
7946                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7947                                 ins->inst_p0 = d;
7948                                 MONO_ADD_INS (bblock, ins);
7949                         }
7950                         ++ip;
7951                         readr8 (ip, d);
7952                         ip += 8;
7953                         *sp++ = ins;
7954                         break;
7955                 }
7956                 case CEE_DUP: {
7957                         MonoInst *temp, *store;
7958                         CHECK_STACK (1);
7959                         CHECK_STACK_OVF (1);
7960                         sp--;
7961                         ins = *sp;
7962
7963                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7964                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7965
7966                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7967                         *sp++ = ins;
7968
7969                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7970                         *sp++ = ins;
7971
7972                         ++ip;
7973                         inline_costs += 2;
7974                         break;
7975                 }
7976                 case CEE_POP:
7977                         CHECK_STACK (1);
7978                         ip++;
7979                         --sp;
7980
7981 #ifdef TARGET_X86
7982                         if (sp [0]->type == STACK_R8)
7983                                 /* we need to pop the value from the x86 FP stack */
7984                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7985 #endif
7986                         break;
7987                 case CEE_JMP: {
7988                         MonoCallInst *call;
7989
7990                         INLINE_FAILURE ("jmp");
7991                         GSHAREDVT_FAILURE (*ip);
7992
7993                         CHECK_OPSIZE (5);
7994                         if (stack_start != sp)
7995                                 UNVERIFIED;
7996                         token = read32 (ip + 1);
7997                         /* FIXME: check the signature matches */
7998                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7999
8000                         if (!cmethod || mono_loader_get_last_error ())
8001                                 LOAD_ERROR;
8002  
8003                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8004                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8005
8006                         if (mono_security_cas_enabled ())
8007                                 CHECK_CFG_EXCEPTION;
8008
8009                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8010
8011                         if (ARCH_HAVE_OP_TAIL_CALL) {
8012                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8013                                 int i, n;
8014
8015                                 /* Handle tail calls similarly to calls */
8016                                 n = fsig->param_count + fsig->hasthis;
8017
8018                                 DISABLE_AOT (cfg);
8019
8020                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8021                                 call->method = cmethod;
8022                                 call->tail_call = TRUE;
8023                                 call->signature = mono_method_signature (cmethod);
8024                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8025                                 call->inst.inst_p0 = cmethod;
8026                                 for (i = 0; i < n; ++i)
8027                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8028
8029                                 mono_arch_emit_call (cfg, call);
8030                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8031                                 MONO_ADD_INS (bblock, (MonoInst*)call);
8032                         } else {
8033                                 for (i = 0; i < num_args; ++i)
8034                                         /* Prevent arguments from being optimized away */
8035                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8036
8037                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8038                                 ins = (MonoInst*)call;
8039                                 ins->inst_p0 = cmethod;
8040                                 MONO_ADD_INS (bblock, ins);
8041                         }
8042
8043                         ip += 5;
8044                         start_new_bblock = 1;
8045                         break;
8046                 }
8047                 case CEE_CALLI:
8048                 case CEE_CALL:
8049                 case CEE_CALLVIRT: {
8050                         MonoInst *addr = NULL;
8051                         MonoMethodSignature *fsig = NULL;
8052                         int array_rank = 0;
8053                         int virtual = *ip == CEE_CALLVIRT;
8054                         int calli = *ip == CEE_CALLI;
8055                         gboolean pass_imt_from_rgctx = FALSE;
8056                         MonoInst *imt_arg = NULL;
8057                         MonoInst *keep_this_alive = NULL;
8058                         gboolean pass_vtable = FALSE;
8059                         gboolean pass_mrgctx = FALSE;
8060                         MonoInst *vtable_arg = NULL;
8061                         gboolean check_this = FALSE;
8062                         gboolean supported_tail_call = FALSE;
8063                         gboolean tail_call = FALSE;
8064                         gboolean need_seq_point = FALSE;
8065                         guint32 call_opcode = *ip;
8066                         gboolean emit_widen = TRUE;
8067                         gboolean push_res = TRUE;
8068                         gboolean skip_ret = FALSE;
8069                         gboolean delegate_invoke = FALSE;
8070
8071                         CHECK_OPSIZE (5);
8072                         token = read32 (ip + 1);
8073
8074                         ins = NULL;
8075
8076                         if (calli) {
8077                                 //GSHAREDVT_FAILURE (*ip);
8078                                 cmethod = NULL;
8079                                 CHECK_STACK (1);
8080                                 --sp;
8081                                 addr = *sp;
8082                                 fsig = mini_get_signature (method, token, generic_context);
8083                                 n = fsig->param_count + fsig->hasthis;
8084
8085                                 if (method->dynamic && fsig->pinvoke) {
8086                                         MonoInst *args [3];
8087
8088                                         /*
8089                                          * This is a call through a function pointer using a pinvoke
8090                                          * signature. Have to create a wrapper and call that instead.
8091                                          * FIXME: This is very slow, need to create a wrapper at JIT time
8092                                          * instead based on the signature.
8093                                          */
8094                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8095                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
8096                                         args [2] = addr;
8097                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8098                                 }
8099                         } else {
8100                                 MonoMethod *cil_method;
8101
8102                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8103                                 cil_method = cmethod;
8104                                 
8105                                 if (constrained_call) {
8106                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8107                                                 if (cfg->verbose_level > 2)
8108                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8109                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
8110                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
8111                                                           cfg->generic_sharing_context)) {
8112                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context, &cfg->error);
8113                                                         CHECK_CFG_ERROR;
8114                                                 }
8115                                         } else {
8116                                                 if (cfg->verbose_level > 2)
8117                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8118
8119                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8120                                                         /* 
8121                                                          * This is needed since get_method_constrained can't find 
8122                                                          * the method in klass representing a type var.
8123                                                          * The type var is guaranteed to be a reference type in this
8124                                                          * case.
8125                                                          */
8126                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
8127                                                                 g_assert (!cmethod->klass->valuetype);
8128                                                 } else {
8129                                                         cmethod = mono_get_method_constrained_checked (image, token, constrained_call, generic_context, &cil_method, &cfg->error);
8130                                                         CHECK_CFG_ERROR;
8131                                                 }
8132                                         }
8133                                 }
8134                                         
8135                                 if (!cmethod || mono_loader_get_last_error ())
8136                                         LOAD_ERROR;
8137                                 if (!dont_verify && !cfg->skip_visibility) {
8138                                         MonoMethod *target_method = cil_method;
8139                                         if (method->is_inflated) {
8140                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8141                                         }
8142                                         if (!mono_method_can_access_method (method_definition, target_method) &&
8143                                                 !mono_method_can_access_method (method, cil_method))
8144                                                 METHOD_ACCESS_FAILURE (method, cil_method);
8145                                 }
8146
8147                                 if (mono_security_core_clr_enabled ())
8148                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
8149
8150                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8151                                         /* MS.NET seems to silently convert this to a callvirt */
8152                                         virtual = 1;
8153
8154                                 {
8155                                         /*
8156                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8157                                          * converts to a callvirt.
8158                                          *
8159                                          * tests/bug-515884.il is an example of this behavior
8160                                          */
8161                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8162                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8163                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8164                                                 virtual = 1;
8165                                 }
8166
8167                                 if (!cmethod->klass->inited)
8168                                         if (!mono_class_init (cmethod->klass))
8169                                                 TYPE_LOAD_ERROR (cmethod->klass);
8170
8171                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8172                                     mini_class_is_system_array (cmethod->klass)) {
8173                                         array_rank = cmethod->klass->rank;
8174                                         fsig = mono_method_signature (cmethod);
8175                                 } else {
8176                                         fsig = mono_method_signature (cmethod);
8177
8178                                         if (!fsig)
8179                                                 LOAD_ERROR;
8180
8181                                         if (fsig->pinvoke) {
8182                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8183                                                         check_for_pending_exc, cfg->compile_aot);
8184                                                 fsig = mono_method_signature (wrapper);
8185                                         } else if (constrained_call) {
8186                                                 fsig = mono_method_signature (cmethod);
8187                                         } else {
8188                                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8189                                                 CHECK_CFG_ERROR;
8190                                         }
8191                                 }
8192
8193                                 mono_save_token_info (cfg, image, token, cil_method);
8194
8195                                 if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8196                                         need_seq_point = TRUE;
8197
8198                                 n = fsig->param_count + fsig->hasthis;
8199
8200                                 /* Don't support calls made using type arguments for now */
8201                                 /*
8202                                 if (cfg->gsharedvt) {
8203                                         if (mini_is_gsharedvt_signature (cfg, fsig))
8204                                                 GSHAREDVT_FAILURE (*ip);
8205                                 }
8206                                 */
8207
8208                                 if (mono_security_cas_enabled ()) {
8209                                         if (check_linkdemand (cfg, method, cmethod))
8210                                                 INLINE_FAILURE ("linkdemand");
8211                                         CHECK_CFG_EXCEPTION;
8212                                 }
8213
8214                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8215                                         g_assert_not_reached ();
8216                         }
8217
8218                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
8219                                 UNVERIFIED;
8220
8221                         if (!cfg->generic_sharing_context && cmethod)
8222                                 g_assert (!mono_method_check_context_used (cmethod));
8223
8224                         CHECK_STACK (n);
8225
8226                         //g_assert (!virtual || fsig->hasthis);
8227
8228                         sp -= n;
8229
8230                         if (constrained_call) {
8231                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
8232                                         /*
8233                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
8234                                          */
8235                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
8236                                                 /* The 'Own method' case below */
8237                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8238                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8239                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
8240                                                            (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)) &&
8241                                                            (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]))))) {
8242                                                 MonoInst *args [16];
8243
8244                                                 /*
8245                                                  * This case handles calls to
8246                                                  * - object:ToString()/Equals()/GetHashCode(),
8247                                                  * - System.IComparable<T>:CompareTo()
8248                                                  * - System.IEquatable<T>:Equals ()
8249                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
8250                                                  */
8251
8252                                                 args [0] = sp [0];
8253                                                 if (mono_method_check_context_used (cmethod))
8254                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
8255                                                 else
8256                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
8257                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
8258
8259                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
8260                                                 if (fsig->hasthis && fsig->param_count) {
8261                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
8262                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
8263                                                         ins->dreg = alloc_preg (cfg);
8264                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
8265                                                         MONO_ADD_INS (cfg->cbb, ins);
8266                                                         args [4] = ins;
8267
8268                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
8269                                                                 int addr_reg;
8270
8271                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
8272
8273                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
8274                                                                 addr_reg = ins->dreg;
8275                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
8276                                                         } else {
8277                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
8278                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
8279                                                         }
8280                                                 } else {
8281                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
8282                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
8283                                                 }
8284                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
8285                                                 emit_widen = FALSE;
8286
8287                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
8288                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
8289                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
8290                                                         MonoInst *add;
8291
8292                                                         /* Unbox */
8293                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
8294                                                         MONO_ADD_INS (cfg->cbb, add);
8295                                                         /* Load value */
8296                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
8297                                                         MONO_ADD_INS (cfg->cbb, ins);
8298                                                         /* ins represents the call result */
8299                                                 }
8300
8301                                                 goto call_end;
8302                                         } else {
8303                                                 GSHAREDVT_FAILURE (*ip);
8304                                         }
8305                                 }
8306                                 /*
8307                                  * We have the `constrained.' prefix opcode.
8308                                  */
8309                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8310                                         /*
8311                                          * The type parameter is instantiated as a valuetype,
8312                                          * but that type doesn't override the method we're
8313                                          * calling, so we need to box `this'.
8314                                          */
8315                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8316                                         ins->klass = constrained_call;
8317                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8318                                         CHECK_CFG_EXCEPTION;
8319                                 } else if (!constrained_call->valuetype) {
8320                                         int dreg = alloc_ireg_ref (cfg);
8321
8322                                         /*
8323                                          * The type parameter is instantiated as a reference
8324                                          * type.  We have a managed pointer on the stack, so
8325                                          * we need to dereference it here.
8326                                          */
8327                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8328                                         ins->type = STACK_OBJ;
8329                                         sp [0] = ins;
8330                                 } else {
8331                                         if (cmethod->klass->valuetype) {
8332                                                 /* Own method */
8333                                         } else {
8334                                                 /* Interface method */
8335                                                 int ioffset, slot;
8336
8337                                                 mono_class_setup_vtable (constrained_call);
8338                                                 CHECK_TYPELOAD (constrained_call);
8339                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8340                                                 if (ioffset == -1)
8341                                                         TYPE_LOAD_ERROR (constrained_call);
8342                                                 slot = mono_method_get_vtable_slot (cmethod);
8343                                                 if (slot == -1)
8344                                                         TYPE_LOAD_ERROR (cmethod->klass);
8345                                                 cmethod = constrained_call->vtable [ioffset + slot];
8346
8347                                                 if (cmethod->klass == mono_defaults.enum_class) {
8348                                                         /* Enum implements some interfaces, so treat this as the first case */
8349                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8350                                                         ins->klass = constrained_call;
8351                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8352                                                         CHECK_CFG_EXCEPTION;
8353                                                 }
8354                                         }
8355                                         virtual = 0;
8356                                 }
8357                                 constrained_call = NULL;
8358                         }
8359
8360                         if (!calli && check_call_signature (cfg, fsig, sp))
8361                                 UNVERIFIED;
8362
8363 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8364                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8365                                 delegate_invoke = TRUE;
8366 #endif
8367
8368                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8369                                 bblock = cfg->cbb;
8370                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8371                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8372                                         emit_widen = FALSE;
8373                                 }
8374
8375                                 goto call_end;
8376                         }
8377
8378                         /* 
8379                          * If the callee is a shared method, then its static cctor
8380                          * might not get called after the call was patched.
8381                          */
8382                         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)) {
8383                                 emit_generic_class_init (cfg, cmethod->klass);
8384                                 CHECK_TYPELOAD (cmethod->klass);
8385                         }
8386
8387                         if (cmethod)
8388                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8389
8390                         if (cfg->generic_sharing_context && cmethod) {
8391                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8392
8393                                 context_used = mini_method_check_context_used (cfg, cmethod);
8394
8395                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8396                                         /* Generic method interface
8397                                            calls are resolved via a
8398                                            helper function and don't
8399                                            need an imt. */
8400                                         if (!cmethod_context || !cmethod_context->method_inst)
8401                                                 pass_imt_from_rgctx = TRUE;
8402                                 }
8403
8404                                 /*
8405                                  * If a shared method calls another
8406                                  * shared method then the caller must
8407                                  * have a generic sharing context
8408                                  * because the magic trampoline
8409                                  * requires it.  FIXME: We shouldn't
8410                                  * have to force the vtable/mrgctx
8411                                  * variable here.  Instead there
8412                                  * should be a flag in the cfg to
8413                                  * request a generic sharing context.
8414                                  */
8415                                 if (context_used &&
8416                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8417                                         mono_get_vtable_var (cfg);
8418                         }
8419
8420                         if (pass_vtable) {
8421                                 if (context_used) {
8422                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8423                                 } else {
8424                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8425
8426                                         CHECK_TYPELOAD (cmethod->klass);
8427                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8428                                 }
8429                         }
8430
8431                         if (pass_mrgctx) {
8432                                 g_assert (!vtable_arg);
8433
8434                                 if (!cfg->compile_aot) {
8435                                         /* 
8436                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8437                                          * for type load errors before.
8438                                          */
8439                                         mono_class_setup_vtable (cmethod->klass);
8440                                         CHECK_TYPELOAD (cmethod->klass);
8441                                 }
8442
8443                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8444
8445                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8446                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8447                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8448                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8449                                         if (virtual)
8450                                                 check_this = TRUE;
8451                                         virtual = 0;
8452                                 }
8453                         }
8454
8455                         if (pass_imt_from_rgctx) {
8456                                 g_assert (!pass_vtable);
8457                                 g_assert (cmethod);
8458
8459                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8460                                         cmethod, MONO_RGCTX_INFO_METHOD);
8461                         }
8462
8463                         if (check_this)
8464                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8465
8466                         /* Calling virtual generic methods */
8467                         if (cmethod && virtual && 
8468                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8469                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8470                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8471                             fsig->generic_param_count && 
8472                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8473                                 MonoInst *this_temp, *this_arg_temp, *store;
8474                                 MonoInst *iargs [4];
8475                                 gboolean use_imt = FALSE;
8476
8477                                 g_assert (fsig->is_inflated);
8478
8479                                 /* Prevent inlining of methods that contain indirect calls */
8480                                 INLINE_FAILURE ("virtual generic call");
8481
8482                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8483                                         GSHAREDVT_FAILURE (*ip);
8484
8485 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8486                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8487                                         use_imt = TRUE;
8488 #endif
8489
8490                                 if (use_imt) {
8491                                         g_assert (!imt_arg);
8492                                         if (!context_used)
8493                                                 g_assert (cmethod->is_inflated);
8494                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8495                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8496                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8497                                 } else {
8498                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8499                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8500                                         MONO_ADD_INS (bblock, store);
8501
8502                                         /* FIXME: This should be a managed pointer */
8503                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8504
8505                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8506                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8507                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8508                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8509                                         addr = mono_emit_jit_icall (cfg,
8510                                                                                                 mono_helper_compile_generic_method, iargs);
8511
8512                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8513
8514                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8515                                 }
8516
8517                                 goto call_end;
8518                         }
8519
8520                         /*
8521                          * Implement a workaround for the inherent races involved in locking:
8522                          * Monitor.Enter ()
8523                          * try {
8524                          * } finally {
8525                          *    Monitor.Exit ()
8526                          * }
8527                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8528                          * try block, the Exit () won't be executed, see:
8529                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8530                          * To work around this, we extend such try blocks to include the last x bytes
8531                          * of the Monitor.Enter () call.
8532                          */
8533                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8534                                 MonoBasicBlock *tbb;
8535
8536                                 GET_BBLOCK (cfg, tbb, ip + 5);
8537                                 /* 
8538                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8539                                  * from Monitor.Enter like ArgumentNullException.
8540                                  */
8541                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8542                                         /* Mark this bblock as needing to be extended */
8543                                         tbb->extend_try_block = TRUE;
8544                                 }
8545                         }
8546
8547                         /* Conversion to a JIT intrinsic */
8548                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8549                                 bblock = cfg->cbb;
8550                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8551                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8552                                         emit_widen = FALSE;
8553                                 }
8554                                 goto call_end;
8555                         }
8556
8557                         /* Inlining */
8558                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8559                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8560                             mono_method_check_inlining (cfg, cmethod)) {
8561                                 int costs;
8562                                 gboolean always = FALSE;
8563
8564                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8565                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8566                                         /* Prevent inlining of methods that call wrappers */
8567                                         INLINE_FAILURE ("wrapper call");
8568                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8569                                         always = TRUE;
8570                                 }
8571
8572                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
8573                                 if (costs) {
8574                                         cfg->real_offset += 5;
8575
8576                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8577                                                 /* *sp is already set by inline_method */
8578                                                 sp++;
8579                                                 push_res = FALSE;
8580                                         }
8581
8582                                         inline_costs += costs;
8583
8584                                         goto call_end;
8585                                 }
8586                         }
8587
8588                         /* Tail recursion elimination */
8589                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8590                                 gboolean has_vtargs = FALSE;
8591                                 int i;
8592
8593                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8594                                 INLINE_FAILURE ("tail call");
8595
8596                                 /* keep it simple */
8597                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8598                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8599                                                 has_vtargs = TRUE;
8600                                 }
8601
8602                                 if (!has_vtargs) {
8603                                         for (i = 0; i < n; ++i)
8604                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8605                                         MONO_INST_NEW (cfg, ins, OP_BR);
8606                                         MONO_ADD_INS (bblock, ins);
8607                                         tblock = start_bblock->out_bb [0];
8608                                         link_bblock (cfg, bblock, tblock);
8609                                         ins->inst_target_bb = tblock;
8610                                         start_new_bblock = 1;
8611
8612                                         /* skip the CEE_RET, too */
8613                                         if (ip_in_bb (cfg, bblock, ip + 5))
8614                                                 skip_ret = TRUE;
8615                                         push_res = FALSE;
8616                                         goto call_end;
8617                                 }
8618                         }
8619
8620                         inline_costs += 10 * num_calls++;
8621
8622                         /*
8623                          * Making generic calls out of gsharedvt methods.
8624                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8625                          * patching gshared method addresses into a gsharedvt method.
8626                          */
8627                         if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class)) {
8628                                 MonoRgctxInfoType info_type;
8629
8630                                 if (virtual) {
8631                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8632                                                 //GSHAREDVT_FAILURE (*ip);
8633                                         // disable for possible remoting calls
8634                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8635                                                 GSHAREDVT_FAILURE (*ip);
8636                                         if (fsig->generic_param_count) {
8637                                                 /* virtual generic call */
8638                                                 g_assert (mono_use_imt);
8639                                                 g_assert (!imt_arg);
8640                                                 /* Same as the virtual generic case above */
8641                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8642                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8643                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8644                                                 vtable_arg = NULL;
8645                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
8646                                                 /* This can happen when we call a fully instantiated iface method */
8647                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8648                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8649                                                 vtable_arg = NULL;
8650                                         }
8651                                 }
8652
8653                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8654                                         /* test_0_multi_dim_arrays () in gshared.cs */
8655                                         GSHAREDVT_FAILURE (*ip);
8656
8657                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8658                                         keep_this_alive = sp [0];
8659
8660                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8661                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8662                                 else
8663                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8664                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8665
8666                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8667                                 goto call_end;
8668                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8669                                 /*
8670                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8671                                  */
8672                                 MonoInst *callee = addr;
8673
8674                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8675                                         /* Not tested */
8676                                         GSHAREDVT_FAILURE (*ip);
8677
8678                                 addr = emit_get_rgctx_sig (cfg, context_used,
8679                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8680                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8681                                 goto call_end;
8682                         }
8683
8684                         /* Generic sharing */
8685
8686                         /*
8687                          * Use this if the callee is gsharedvt sharable too, since
8688                          * at runtime we might find an instantiation so the call cannot
8689                          * be patched (the 'no_patch' code path in mini-trampolines.c).
8690                          */
8691                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8692                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
8693                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8694                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8695                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8696                                 INLINE_FAILURE ("gshared");
8697
8698                                 g_assert (cfg->generic_sharing_context && cmethod);
8699                                 g_assert (!addr);
8700
8701                                 /*
8702                                  * We are compiling a call to a
8703                                  * generic method from shared code,
8704                                  * which means that we have to look up
8705                                  * the method in the rgctx and do an
8706                                  * indirect call.
8707                                  */
8708                                 if (fsig->hasthis)
8709                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8710
8711                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8712                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8713                                 goto call_end;
8714                         }
8715
8716                         /* Indirect calls */
8717                         if (addr) {
8718                                 if (call_opcode == CEE_CALL)
8719                                         g_assert (context_used);
8720                                 else if (call_opcode == CEE_CALLI)
8721                                         g_assert (!vtable_arg);
8722                                 else
8723                                         /* FIXME: what the hell is this??? */
8724                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8725                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8726
8727                                 /* Prevent inlining of methods with indirect calls */
8728                                 INLINE_FAILURE ("indirect call");
8729
8730                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8731                                         int info_type;
8732                                         gpointer info_data;
8733
8734                                         /* 
8735                                          * Instead of emitting an indirect call, emit a direct call
8736                                          * with the contents of the aotconst as the patch info.
8737                                          */
8738                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8739                                                 info_type = addr->inst_c1;
8740                                                 info_data = addr->inst_p0;
8741                                         } else {
8742                                                 info_type = addr->inst_right->inst_c1;
8743                                                 info_data = addr->inst_right->inst_left;
8744                                         }
8745                                         
8746                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8747                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8748                                                 NULLIFY_INS (addr);
8749                                                 goto call_end;
8750                                         }
8751                                 }
8752                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8753                                 goto call_end;
8754                         }
8755                                         
8756                         /* Array methods */
8757                         if (array_rank) {
8758                                 MonoInst *addr;
8759
8760                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8761                                         MonoInst *val = sp [fsig->param_count];
8762
8763                                         if (val->type == STACK_OBJ) {
8764                                                 MonoInst *iargs [2];
8765
8766                                                 iargs [0] = sp [0];
8767                                                 iargs [1] = val;
8768                                                 
8769                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8770                                         }
8771                                         
8772                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8773                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8774                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8775                                                 emit_write_barrier (cfg, addr, val);
8776                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8777                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8778
8779                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8780                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8781                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8782                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8783                                         CHECK_TYPELOAD (cmethod->klass);
8784                                         
8785                                         readonly = FALSE;
8786                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8787                                         ins = addr;
8788                                 } else {
8789                                         g_assert_not_reached ();
8790                                 }
8791
8792                                 emit_widen = FALSE;
8793                                 goto call_end;
8794                         }
8795
8796                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8797                         if (ins)
8798                                 goto call_end;
8799
8800                         /* Tail prefix / tail call optimization */
8801
8802                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8803                         /* FIXME: runtime generic context pointer for jumps? */
8804                         /* FIXME: handle this for generic sharing eventually */
8805                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8806                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
8807                                 supported_tail_call = TRUE;
8808
8809                         if (supported_tail_call) {
8810                                 MonoCallInst *call;
8811
8812                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8813                                 INLINE_FAILURE ("tail call");
8814
8815                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8816
8817                                 if (ARCH_HAVE_OP_TAIL_CALL) {
8818                                         /* Handle tail calls similarly to normal calls */
8819                                         tail_call = TRUE;
8820                                 } else {
8821                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8822
8823                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8824                                         call->tail_call = TRUE;
8825                                         call->method = cmethod;
8826                                         call->signature = mono_method_signature (cmethod);
8827
8828                                         /*
8829                                          * We implement tail calls by storing the actual arguments into the 
8830                                          * argument variables, then emitting a CEE_JMP.
8831                                          */
8832                                         for (i = 0; i < n; ++i) {
8833                                                 /* Prevent argument from being register allocated */
8834                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8835                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8836                                         }
8837                                         ins = (MonoInst*)call;
8838                                         ins->inst_p0 = cmethod;
8839                                         ins->inst_p1 = arg_array [0];
8840                                         MONO_ADD_INS (bblock, ins);
8841                                         link_bblock (cfg, bblock, end_bblock);                  
8842                                         start_new_bblock = 1;
8843
8844                                         // FIXME: Eliminate unreachable epilogs
8845
8846                                         /*
8847                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8848                                          * only reachable from this call.
8849                                          */
8850                                         GET_BBLOCK (cfg, tblock, ip + 5);
8851                                         if (tblock == bblock || tblock->in_count == 0)
8852                                                 skip_ret = TRUE;
8853                                         push_res = FALSE;
8854
8855                                         goto call_end;
8856                                 }
8857                         }
8858
8859                         /* 
8860                          * Synchronized wrappers.
8861                          * Its hard to determine where to replace a method with its synchronized
8862                          * wrapper without causing an infinite recursion. The current solution is
8863                          * to add the synchronized wrapper in the trampolines, and to
8864                          * change the called method to a dummy wrapper, and resolve that wrapper
8865                          * to the real method in mono_jit_compile_method ().
8866                          */
8867                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8868                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8869                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8870                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8871                         }
8872
8873                         /* Common call */
8874                         INLINE_FAILURE ("call");
8875                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8876                                                                                           imt_arg, vtable_arg);
8877
8878                         if (tail_call) {
8879                                 link_bblock (cfg, bblock, end_bblock);                  
8880                                 start_new_bblock = 1;
8881
8882                                 // FIXME: Eliminate unreachable epilogs
8883
8884                                 /*
8885                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8886                                  * only reachable from this call.
8887                                  */
8888                                 GET_BBLOCK (cfg, tblock, ip + 5);
8889                                 if (tblock == bblock || tblock->in_count == 0)
8890                                         skip_ret = TRUE;
8891                                 push_res = FALSE;
8892                         }
8893
8894                         call_end:
8895
8896                         /* End of call, INS should contain the result of the call, if any */
8897
8898                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8899                                 g_assert (ins);
8900                                 if (emit_widen)
8901                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8902                                 else
8903                                         *sp++ = ins;
8904                         }
8905
8906                         if (keep_this_alive) {
8907                                 MonoInst *dummy_use;
8908
8909                                 /* See mono_emit_method_call_full () */
8910                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8911                         }
8912
8913                         CHECK_CFG_EXCEPTION;
8914
8915                         ip += 5;
8916                         if (skip_ret) {
8917                                 g_assert (*ip == CEE_RET);
8918                                 ip += 1;
8919                         }
8920                         ins_flag = 0;
8921                         constrained_call = NULL;
8922                         if (need_seq_point)
8923                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8924                         break;
8925                 }
8926                 case CEE_RET:
8927                         if (cfg->method != method) {
8928                                 /* return from inlined method */
8929                                 /* 
8930                                  * If in_count == 0, that means the ret is unreachable due to
8931                                  * being preceeded by a throw. In that case, inline_method () will
8932                                  * handle setting the return value 
8933                                  * (test case: test_0_inline_throw ()).
8934                                  */
8935                                 if (return_var && cfg->cbb->in_count) {
8936                                         MonoType *ret_type = mono_method_signature (method)->ret;
8937
8938                                         MonoInst *store;
8939                                         CHECK_STACK (1);
8940                                         --sp;
8941
8942                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8943                                                 UNVERIFIED;
8944
8945                                         //g_assert (returnvar != -1);
8946                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8947                                         cfg->ret_var_set = TRUE;
8948                                 } 
8949                         } else {
8950                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
8951
8952                                 if (cfg->lmf_var && cfg->cbb->in_count)
8953                                         emit_pop_lmf (cfg);
8954
8955                                 if (cfg->ret) {
8956                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
8957
8958                                         if (seq_points && !sym_seq_points) {
8959                                                 /* 
8960                                                  * Place a seq point here too even through the IL stack is not
8961                                                  * empty, so a step over on
8962                                                  * call <FOO>
8963                                                  * ret
8964                                                  * will work correctly.
8965                                                  */
8966                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8967                                                 MONO_ADD_INS (cfg->cbb, ins);
8968                                         }
8969
8970                                         g_assert (!return_var);
8971                                         CHECK_STACK (1);
8972                                         --sp;
8973
8974                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8975                                                 UNVERIFIED;
8976
8977                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8978                                                 MonoInst *ret_addr;
8979
8980                                                 if (!cfg->vret_addr) {
8981                                                         MonoInst *ins;
8982
8983                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8984                                                 } else {
8985                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8986
8987                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8988                                                         ins->klass = mono_class_from_mono_type (ret_type);
8989                                                 }
8990                                         } else {
8991 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8992                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8993                                                         MonoInst *iargs [1];
8994                                                         MonoInst *conv;
8995
8996                                                         iargs [0] = *sp;
8997                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8998                                                         mono_arch_emit_setret (cfg, method, conv);
8999                                                 } else {
9000                                                         mono_arch_emit_setret (cfg, method, *sp);
9001                                                 }
9002 #else
9003                                                 mono_arch_emit_setret (cfg, method, *sp);
9004 #endif
9005                                         }
9006                                 }
9007                         }
9008                         if (sp != stack_start)
9009                                 UNVERIFIED;
9010                         MONO_INST_NEW (cfg, ins, OP_BR);
9011                         ip++;
9012                         ins->inst_target_bb = end_bblock;
9013                         MONO_ADD_INS (bblock, ins);
9014                         link_bblock (cfg, bblock, end_bblock);
9015                         start_new_bblock = 1;
9016                         break;
9017                 case CEE_BR_S:
9018                         CHECK_OPSIZE (2);
9019                         MONO_INST_NEW (cfg, ins, OP_BR);
9020                         ip++;
9021                         target = ip + 1 + (signed char)(*ip);
9022                         ++ip;
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                         MONO_ADD_INS (bblock, ins);
9032                         start_new_bblock = 1;
9033                         inline_costs += BRANCH_COST;
9034                         break;
9035                 case CEE_BEQ_S:
9036                 case CEE_BGE_S:
9037                 case CEE_BGT_S:
9038                 case CEE_BLE_S:
9039                 case CEE_BLT_S:
9040                 case CEE_BNE_UN_S:
9041                 case CEE_BGE_UN_S:
9042                 case CEE_BGT_UN_S:
9043                 case CEE_BLE_UN_S:
9044                 case CEE_BLT_UN_S:
9045                         CHECK_OPSIZE (2);
9046                         CHECK_STACK (2);
9047                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9048                         ip++;
9049                         target = ip + 1 + *(signed char*)ip;
9050                         ip++;
9051
9052                         ADD_BINCOND (NULL);
9053
9054                         sp = stack_start;
9055                         inline_costs += BRANCH_COST;
9056                         break;
9057                 case CEE_BR:
9058                         CHECK_OPSIZE (5);
9059                         MONO_INST_NEW (cfg, ins, OP_BR);
9060                         ip++;
9061
9062                         target = ip + 4 + (gint32)read32(ip);
9063                         ip += 4;
9064                         GET_BBLOCK (cfg, tblock, target);
9065                         link_bblock (cfg, bblock, tblock);
9066                         ins->inst_target_bb = tblock;
9067                         if (sp != stack_start) {
9068                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9069                                 sp = stack_start;
9070                                 CHECK_UNVERIFIABLE (cfg);
9071                         }
9072
9073                         MONO_ADD_INS (bblock, ins);
9074
9075                         start_new_bblock = 1;
9076                         inline_costs += BRANCH_COST;
9077                         break;
9078                 case CEE_BRFALSE_S:
9079                 case CEE_BRTRUE_S:
9080                 case CEE_BRFALSE:
9081                 case CEE_BRTRUE: {
9082                         MonoInst *cmp;
9083                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9084                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9085                         guint32 opsize = is_short ? 1 : 4;
9086
9087                         CHECK_OPSIZE (opsize);
9088                         CHECK_STACK (1);
9089                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9090                                 UNVERIFIED;
9091                         ip ++;
9092                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9093                         ip += opsize;
9094
9095                         sp--;
9096
9097                         GET_BBLOCK (cfg, tblock, target);
9098                         link_bblock (cfg, bblock, tblock);
9099                         GET_BBLOCK (cfg, tblock, ip);
9100                         link_bblock (cfg, bblock, tblock);
9101
9102                         if (sp != stack_start) {
9103                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9104                                 CHECK_UNVERIFIABLE (cfg);
9105                         }
9106
9107                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9108                         cmp->sreg1 = sp [0]->dreg;
9109                         type_from_op (cmp, sp [0], NULL);
9110                         CHECK_TYPE (cmp);
9111
9112 #if SIZEOF_REGISTER == 4
9113                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9114                                 /* Convert it to OP_LCOMPARE */
9115                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9116                                 ins->type = STACK_I8;
9117                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9118                                 ins->inst_l = 0;
9119                                 MONO_ADD_INS (bblock, ins);
9120                                 cmp->opcode = OP_LCOMPARE;
9121                                 cmp->sreg2 = ins->dreg;
9122                         }
9123 #endif
9124                         MONO_ADD_INS (bblock, cmp);
9125
9126                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9127                         type_from_op (ins, sp [0], NULL);
9128                         MONO_ADD_INS (bblock, ins);
9129                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9130                         GET_BBLOCK (cfg, tblock, target);
9131                         ins->inst_true_bb = tblock;
9132                         GET_BBLOCK (cfg, tblock, ip);
9133                         ins->inst_false_bb = tblock;
9134                         start_new_bblock = 2;
9135
9136                         sp = stack_start;
9137                         inline_costs += BRANCH_COST;
9138                         break;
9139                 }
9140                 case CEE_BEQ:
9141                 case CEE_BGE:
9142                 case CEE_BGT:
9143                 case CEE_BLE:
9144                 case CEE_BLT:
9145                 case CEE_BNE_UN:
9146                 case CEE_BGE_UN:
9147                 case CEE_BGT_UN:
9148                 case CEE_BLE_UN:
9149                 case CEE_BLT_UN:
9150                         CHECK_OPSIZE (5);
9151                         CHECK_STACK (2);
9152                         MONO_INST_NEW (cfg, ins, *ip);
9153                         ip++;
9154                         target = ip + 4 + (gint32)read32(ip);
9155                         ip += 4;
9156
9157                         ADD_BINCOND (NULL);
9158
9159                         sp = stack_start;
9160                         inline_costs += BRANCH_COST;
9161                         break;
9162                 case CEE_SWITCH: {
9163                         MonoInst *src1;
9164                         MonoBasicBlock **targets;
9165                         MonoBasicBlock *default_bblock;
9166                         MonoJumpInfoBBTable *table;
9167                         int offset_reg = alloc_preg (cfg);
9168                         int target_reg = alloc_preg (cfg);
9169                         int table_reg = alloc_preg (cfg);
9170                         int sum_reg = alloc_preg (cfg);
9171                         gboolean use_op_switch;
9172
9173                         CHECK_OPSIZE (5);
9174                         CHECK_STACK (1);
9175                         n = read32 (ip + 1);
9176                         --sp;
9177                         src1 = sp [0];
9178                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9179                                 UNVERIFIED;
9180
9181                         ip += 5;
9182                         CHECK_OPSIZE (n * sizeof (guint32));
9183                         target = ip + n * sizeof (guint32);
9184
9185                         GET_BBLOCK (cfg, default_bblock, target);
9186                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9187
9188                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9189                         for (i = 0; i < n; ++i) {
9190                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9191                                 targets [i] = tblock;
9192                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9193                                 ip += 4;
9194                         }
9195
9196                         if (sp != stack_start) {
9197                                 /* 
9198                                  * Link the current bb with the targets as well, so handle_stack_args
9199                                  * will set their in_stack correctly.
9200                                  */
9201                                 link_bblock (cfg, bblock, default_bblock);
9202                                 for (i = 0; i < n; ++i)
9203                                         link_bblock (cfg, bblock, targets [i]);
9204
9205                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9206                                 sp = stack_start;
9207                                 CHECK_UNVERIFIABLE (cfg);
9208                         }
9209
9210                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9211                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9212                         bblock = cfg->cbb;
9213
9214                         for (i = 0; i < n; ++i)
9215                                 link_bblock (cfg, bblock, targets [i]);
9216
9217                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9218                         table->table = targets;
9219                         table->table_size = n;
9220
9221                         use_op_switch = FALSE;
9222 #ifdef TARGET_ARM
9223                         /* ARM implements SWITCH statements differently */
9224                         /* FIXME: Make it use the generic implementation */
9225                         if (!cfg->compile_aot)
9226                                 use_op_switch = TRUE;
9227 #endif
9228
9229                         if (COMPILE_LLVM (cfg))
9230                                 use_op_switch = TRUE;
9231
9232                         cfg->cbb->has_jump_table = 1;
9233
9234                         if (use_op_switch) {
9235                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9236                                 ins->sreg1 = src1->dreg;
9237                                 ins->inst_p0 = table;
9238                                 ins->inst_many_bb = targets;
9239                                 ins->klass = GUINT_TO_POINTER (n);
9240                                 MONO_ADD_INS (cfg->cbb, ins);
9241                         } else {
9242                                 if (sizeof (gpointer) == 8)
9243                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9244                                 else
9245                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9246
9247 #if SIZEOF_REGISTER == 8
9248                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9249                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9250 #endif
9251
9252                                 if (cfg->compile_aot) {
9253                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9254                                 } else {
9255                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9256                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9257                                         ins->inst_p0 = table;
9258                                         ins->dreg = table_reg;
9259                                         MONO_ADD_INS (cfg->cbb, ins);
9260                                 }
9261
9262                                 /* FIXME: Use load_memindex */
9263                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9264                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9265                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9266                         }
9267                         start_new_bblock = 1;
9268                         inline_costs += (BRANCH_COST * 2);
9269                         break;
9270                 }
9271                 case CEE_LDIND_I1:
9272                 case CEE_LDIND_U1:
9273                 case CEE_LDIND_I2:
9274                 case CEE_LDIND_U2:
9275                 case CEE_LDIND_I4:
9276                 case CEE_LDIND_U4:
9277                 case CEE_LDIND_I8:
9278                 case CEE_LDIND_I:
9279                 case CEE_LDIND_R4:
9280                 case CEE_LDIND_R8:
9281                 case CEE_LDIND_REF:
9282                         CHECK_STACK (1);
9283                         --sp;
9284
9285                         switch (*ip) {
9286                         case CEE_LDIND_R4:
9287                         case CEE_LDIND_R8:
9288                                 dreg = alloc_freg (cfg);
9289                                 break;
9290                         case CEE_LDIND_I8:
9291                                 dreg = alloc_lreg (cfg);
9292                                 break;
9293                         case CEE_LDIND_REF:
9294                                 dreg = alloc_ireg_ref (cfg);
9295                                 break;
9296                         default:
9297                                 dreg = alloc_preg (cfg);
9298                         }
9299
9300                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9301                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9302                         ins->flags |= ins_flag;
9303                         MONO_ADD_INS (bblock, ins);
9304                         *sp++ = ins;
9305                         if (ins_flag & MONO_INST_VOLATILE) {
9306                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9307                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9308                                 emit_memory_barrier (cfg, FullBarrier);
9309                         }
9310                         ins_flag = 0;
9311                         ++ip;
9312                         break;
9313                 case CEE_STIND_REF:
9314                 case CEE_STIND_I1:
9315                 case CEE_STIND_I2:
9316                 case CEE_STIND_I4:
9317                 case CEE_STIND_I8:
9318                 case CEE_STIND_R4:
9319                 case CEE_STIND_R8:
9320                 case CEE_STIND_I:
9321                         CHECK_STACK (2);
9322                         sp -= 2;
9323
9324                         if (ins_flag & MONO_INST_VOLATILE) {
9325                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9326                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9327                                 emit_memory_barrier (cfg, FullBarrier);
9328                         }
9329
9330                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9331                         ins->flags |= ins_flag;
9332                         ins_flag = 0;
9333
9334                         MONO_ADD_INS (bblock, ins);
9335
9336                         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)))
9337                                 emit_write_barrier (cfg, sp [0], sp [1]);
9338
9339                         inline_costs += 1;
9340                         ++ip;
9341                         break;
9342
9343                 case CEE_MUL:
9344                         CHECK_STACK (2);
9345
9346                         MONO_INST_NEW (cfg, ins, (*ip));
9347                         sp -= 2;
9348                         ins->sreg1 = sp [0]->dreg;
9349                         ins->sreg2 = sp [1]->dreg;
9350                         type_from_op (ins, sp [0], sp [1]);
9351                         CHECK_TYPE (ins);
9352                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9353
9354                         /* Use the immediate opcodes if possible */
9355                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9356                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9357                                 if (imm_opcode != -1) {
9358                                         ins->opcode = imm_opcode;
9359                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9360                                         ins->sreg2 = -1;
9361
9362                                         NULLIFY_INS (sp [1]);
9363                                 }
9364                         }
9365
9366                         MONO_ADD_INS ((cfg)->cbb, (ins));
9367
9368                         *sp++ = mono_decompose_opcode (cfg, ins);
9369                         ip++;
9370                         break;
9371                 case CEE_ADD:
9372                 case CEE_SUB:
9373                 case CEE_DIV:
9374                 case CEE_DIV_UN:
9375                 case CEE_REM:
9376                 case CEE_REM_UN:
9377                 case CEE_AND:
9378                 case CEE_OR:
9379                 case CEE_XOR:
9380                 case CEE_SHL:
9381                 case CEE_SHR:
9382                 case CEE_SHR_UN:
9383                         CHECK_STACK (2);
9384
9385                         MONO_INST_NEW (cfg, ins, (*ip));
9386                         sp -= 2;
9387                         ins->sreg1 = sp [0]->dreg;
9388                         ins->sreg2 = sp [1]->dreg;
9389                         type_from_op (ins, sp [0], sp [1]);
9390                         CHECK_TYPE (ins);
9391                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
9392                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9393
9394                         /* FIXME: Pass opcode to is_inst_imm */
9395
9396                         /* Use the immediate opcodes if possible */
9397                         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)) {
9398                                 int imm_opcode;
9399
9400                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9401 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9402                                 /* Keep emulated opcodes which are optimized away later */
9403                                 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) {
9404                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9405                                 }
9406 #endif
9407                                 if (imm_opcode != -1) {
9408                                         ins->opcode = imm_opcode;
9409                                         if (sp [1]->opcode == OP_I8CONST) {
9410 #if SIZEOF_REGISTER == 8
9411                                                 ins->inst_imm = sp [1]->inst_l;
9412 #else
9413                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9414                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9415 #endif
9416                                         }
9417                                         else
9418                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9419                                         ins->sreg2 = -1;
9420
9421                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
9422                                         if (sp [1]->next == NULL)
9423                                                 NULLIFY_INS (sp [1]);
9424                                 }
9425                         }
9426                         MONO_ADD_INS ((cfg)->cbb, (ins));
9427
9428                         *sp++ = mono_decompose_opcode (cfg, ins);
9429                         ip++;
9430                         break;
9431                 case CEE_NEG:
9432                 case CEE_NOT:
9433                 case CEE_CONV_I1:
9434                 case CEE_CONV_I2:
9435                 case CEE_CONV_I4:
9436                 case CEE_CONV_R4:
9437                 case CEE_CONV_R8:
9438                 case CEE_CONV_U4:
9439                 case CEE_CONV_I8:
9440                 case CEE_CONV_U8:
9441                 case CEE_CONV_OVF_I8:
9442                 case CEE_CONV_OVF_U8:
9443                 case CEE_CONV_R_UN:
9444                         CHECK_STACK (1);
9445
9446                         /* Special case this earlier so we have long constants in the IR */
9447                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9448                                 int data = sp [-1]->inst_c0;
9449                                 sp [-1]->opcode = OP_I8CONST;
9450                                 sp [-1]->type = STACK_I8;
9451 #if SIZEOF_REGISTER == 8
9452                                 if ((*ip) == CEE_CONV_U8)
9453                                         sp [-1]->inst_c0 = (guint32)data;
9454                                 else
9455                                         sp [-1]->inst_c0 = data;
9456 #else
9457                                 sp [-1]->inst_ls_word = data;
9458                                 if ((*ip) == CEE_CONV_U8)
9459                                         sp [-1]->inst_ms_word = 0;
9460                                 else
9461                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9462 #endif
9463                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9464                         }
9465                         else {
9466                                 ADD_UNOP (*ip);
9467                         }
9468                         ip++;
9469                         break;
9470                 case CEE_CONV_OVF_I4:
9471                 case CEE_CONV_OVF_I1:
9472                 case CEE_CONV_OVF_I2:
9473                 case CEE_CONV_OVF_I:
9474                 case CEE_CONV_OVF_U:
9475                         CHECK_STACK (1);
9476
9477                         if (sp [-1]->type == STACK_R8) {
9478                                 ADD_UNOP (CEE_CONV_OVF_I8);
9479                                 ADD_UNOP (*ip);
9480                         } else {
9481                                 ADD_UNOP (*ip);
9482                         }
9483                         ip++;
9484                         break;
9485                 case CEE_CONV_OVF_U1:
9486                 case CEE_CONV_OVF_U2:
9487                 case CEE_CONV_OVF_U4:
9488                         CHECK_STACK (1);
9489
9490                         if (sp [-1]->type == STACK_R8) {
9491                                 ADD_UNOP (CEE_CONV_OVF_U8);
9492                                 ADD_UNOP (*ip);
9493                         } else {
9494                                 ADD_UNOP (*ip);
9495                         }
9496                         ip++;
9497                         break;
9498                 case CEE_CONV_OVF_I1_UN:
9499                 case CEE_CONV_OVF_I2_UN:
9500                 case CEE_CONV_OVF_I4_UN:
9501                 case CEE_CONV_OVF_I8_UN:
9502                 case CEE_CONV_OVF_U1_UN:
9503                 case CEE_CONV_OVF_U2_UN:
9504                 case CEE_CONV_OVF_U4_UN:
9505                 case CEE_CONV_OVF_U8_UN:
9506                 case CEE_CONV_OVF_I_UN:
9507                 case CEE_CONV_OVF_U_UN:
9508                 case CEE_CONV_U2:
9509                 case CEE_CONV_U1:
9510                 case CEE_CONV_I:
9511                 case CEE_CONV_U:
9512                         CHECK_STACK (1);
9513                         ADD_UNOP (*ip);
9514                         CHECK_CFG_EXCEPTION;
9515                         ip++;
9516                         break;
9517                 case CEE_ADD_OVF:
9518                 case CEE_ADD_OVF_UN:
9519                 case CEE_MUL_OVF:
9520                 case CEE_MUL_OVF_UN:
9521                 case CEE_SUB_OVF:
9522                 case CEE_SUB_OVF_UN:
9523                         CHECK_STACK (2);
9524                         ADD_BINOP (*ip);
9525                         ip++;
9526                         break;
9527                 case CEE_CPOBJ:
9528                         GSHAREDVT_FAILURE (*ip);
9529                         CHECK_OPSIZE (5);
9530                         CHECK_STACK (2);
9531                         token = read32 (ip + 1);
9532                         klass = mini_get_class (method, token, generic_context);
9533                         CHECK_TYPELOAD (klass);
9534                         sp -= 2;
9535                         if (generic_class_is_reference_type (cfg, klass)) {
9536                                 MonoInst *store, *load;
9537                                 int dreg = alloc_ireg_ref (cfg);
9538
9539                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9540                                 load->flags |= ins_flag;
9541                                 MONO_ADD_INS (cfg->cbb, load);
9542
9543                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9544                                 store->flags |= ins_flag;
9545                                 MONO_ADD_INS (cfg->cbb, store);
9546
9547                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9548                                         emit_write_barrier (cfg, sp [0], sp [1]);
9549                         } else {
9550                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9551                         }
9552                         ins_flag = 0;
9553                         ip += 5;
9554                         break;
9555                 case CEE_LDOBJ: {
9556                         int loc_index = -1;
9557                         int stloc_len = 0;
9558
9559                         CHECK_OPSIZE (5);
9560                         CHECK_STACK (1);
9561                         --sp;
9562                         token = read32 (ip + 1);
9563                         klass = mini_get_class (method, token, generic_context);
9564                         CHECK_TYPELOAD (klass);
9565
9566                         /* Optimize the common ldobj+stloc combination */
9567                         switch (ip [5]) {
9568                         case CEE_STLOC_S:
9569                                 loc_index = ip [6];
9570                                 stloc_len = 2;
9571                                 break;
9572                         case CEE_STLOC_0:
9573                         case CEE_STLOC_1:
9574                         case CEE_STLOC_2:
9575                         case CEE_STLOC_3:
9576                                 loc_index = ip [5] - CEE_STLOC_0;
9577                                 stloc_len = 1;
9578                                 break;
9579                         default:
9580                                 break;
9581                         }
9582
9583                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9584                                 CHECK_LOCAL (loc_index);
9585
9586                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9587                                 ins->dreg = cfg->locals [loc_index]->dreg;
9588                                 ins->flags |= ins_flag;
9589                                 ip += 5;
9590                                 ip += stloc_len;
9591                                 if (ins_flag & MONO_INST_VOLATILE) {
9592                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9593                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9594                                         emit_memory_barrier (cfg, FullBarrier);
9595                                 }
9596                                 ins_flag = 0;
9597                                 break;
9598                         }
9599
9600                         /* Optimize the ldobj+stobj combination */
9601                         /* The reference case ends up being a load+store anyway */
9602                         /* Skip this if the operation is volatile. */
9603                         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)) {
9604                                 CHECK_STACK (1);
9605
9606                                 sp --;
9607
9608                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9609
9610                                 ip += 5 + 5;
9611                                 ins_flag = 0;
9612                                 break;
9613                         }
9614
9615                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9616                         ins->flags |= ins_flag;
9617                         *sp++ = ins;
9618
9619                         if (ins_flag & MONO_INST_VOLATILE) {
9620                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9621                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
9622                                 emit_memory_barrier (cfg, FullBarrier);
9623                         }
9624
9625                         ip += 5;
9626                         ins_flag = 0;
9627                         inline_costs += 1;
9628                         break;
9629                 }
9630                 case CEE_LDSTR:
9631                         CHECK_STACK_OVF (1);
9632                         CHECK_OPSIZE (5);
9633                         n = read32 (ip + 1);
9634
9635                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9636                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9637                                 ins->type = STACK_OBJ;
9638                                 *sp = ins;
9639                         }
9640                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9641                                 MonoInst *iargs [1];
9642                                 char *str = mono_method_get_wrapper_data (method, n);
9643
9644                                 if (cfg->compile_aot)
9645                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
9646                                 else
9647                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
9648                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9649                         } else {
9650                                 if (cfg->opt & MONO_OPT_SHARED) {
9651                                         MonoInst *iargs [3];
9652
9653                                         if (cfg->compile_aot) {
9654                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9655                                         }
9656                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9657                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9658                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9659                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9660                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9661                                 } else {
9662                                         if (bblock->out_of_line) {
9663                                                 MonoInst *iargs [2];
9664
9665                                                 if (image == mono_defaults.corlib) {
9666                                                         /* 
9667                                                          * Avoid relocations in AOT and save some space by using a 
9668                                                          * version of helper_ldstr specialized to mscorlib.
9669                                                          */
9670                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9671                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9672                                                 } else {
9673                                                         /* Avoid creating the string object */
9674                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9675                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9676                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9677                                                 }
9678                                         } 
9679                                         else
9680                                         if (cfg->compile_aot) {
9681                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9682                                                 *sp = ins;
9683                                                 MONO_ADD_INS (bblock, ins);
9684                                         } 
9685                                         else {
9686                                                 NEW_PCONST (cfg, ins, NULL);
9687                                                 ins->type = STACK_OBJ;
9688                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9689                                                 if (!ins->inst_p0)
9690                                                         OUT_OF_MEMORY_FAILURE;
9691
9692                                                 *sp = ins;
9693                                                 MONO_ADD_INS (bblock, ins);
9694                                         }
9695                                 }
9696                         }
9697
9698                         sp++;
9699                         ip += 5;
9700                         break;
9701                 case CEE_NEWOBJ: {
9702                         MonoInst *iargs [2];
9703                         MonoMethodSignature *fsig;
9704                         MonoInst this_ins;
9705                         MonoInst *alloc;
9706                         MonoInst *vtable_arg = NULL;
9707
9708                         CHECK_OPSIZE (5);
9709                         token = read32 (ip + 1);
9710                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9711                         if (!cmethod || mono_loader_get_last_error ())
9712                                 LOAD_ERROR;
9713                         fsig = mono_method_get_signature_checked (cmethod, image, token, NULL, &cfg->error);
9714                         CHECK_CFG_ERROR;
9715
9716                         mono_save_token_info (cfg, image, token, cmethod);
9717
9718                         if (!mono_class_init (cmethod->klass))
9719                                 TYPE_LOAD_ERROR (cmethod->klass);
9720
9721                         context_used = mini_method_check_context_used (cfg, cmethod);
9722
9723                         if (mono_security_cas_enabled ()) {
9724                                 if (check_linkdemand (cfg, method, cmethod))
9725                                         INLINE_FAILURE ("linkdemand");
9726                                 CHECK_CFG_EXCEPTION;
9727                         } else if (mono_security_core_clr_enabled ()) {
9728                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9729                         }
9730
9731                         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)) {
9732                                 emit_generic_class_init (cfg, cmethod->klass);
9733                                 CHECK_TYPELOAD (cmethod->klass);
9734                         }
9735
9736                         /*
9737                         if (cfg->gsharedvt) {
9738                                 if (mini_is_gsharedvt_variable_signature (sig))
9739                                         GSHAREDVT_FAILURE (*ip);
9740                         }
9741                         */
9742
9743                         n = fsig->param_count;
9744                         CHECK_STACK (n);
9745
9746                         /* 
9747                          * Generate smaller code for the common newobj <exception> instruction in
9748                          * argument checking code.
9749                          */
9750                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9751                                 is_exception_class (cmethod->klass) && n <= 2 &&
9752                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9753                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9754                                 MonoInst *iargs [3];
9755
9756                                 sp -= n;
9757
9758                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9759                                 switch (n) {
9760                                 case 0:
9761                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9762                                         break;
9763                                 case 1:
9764                                         iargs [1] = sp [0];
9765                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9766                                         break;
9767                                 case 2:
9768                                         iargs [1] = sp [0];
9769                                         iargs [2] = sp [1];
9770                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9771                                         break;
9772                                 default:
9773                                         g_assert_not_reached ();
9774                                 }
9775
9776                                 ip += 5;
9777                                 inline_costs += 5;
9778                                 break;
9779                         }
9780
9781                         /* move the args to allow room for 'this' in the first position */
9782                         while (n--) {
9783                                 --sp;
9784                                 sp [1] = sp [0];
9785                         }
9786
9787                         /* check_call_signature () requires sp[0] to be set */
9788                         this_ins.type = STACK_OBJ;
9789                         sp [0] = &this_ins;
9790                         if (check_call_signature (cfg, fsig, sp))
9791                                 UNVERIFIED;
9792
9793                         iargs [0] = NULL;
9794
9795                         if (mini_class_is_system_array (cmethod->klass)) {
9796                                 *sp = emit_get_rgctx_method (cfg, context_used,
9797                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9798
9799                                 /* Avoid varargs in the common case */
9800                                 if (fsig->param_count == 1)
9801                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9802                                 else if (fsig->param_count == 2)
9803                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9804                                 else if (fsig->param_count == 3)
9805                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9806                                 else if (fsig->param_count == 4)
9807                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9808                                 else
9809                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9810                         } else if (cmethod->string_ctor) {
9811                                 g_assert (!context_used);
9812                                 g_assert (!vtable_arg);
9813                                 /* we simply pass a null pointer */
9814                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9815                                 /* now call the string ctor */
9816                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9817                         } else {
9818                                 if (cmethod->klass->valuetype) {
9819                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9820                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
9821                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9822
9823                                         alloc = NULL;
9824
9825                                         /* 
9826                                          * The code generated by mini_emit_virtual_call () expects
9827                                          * iargs [0] to be a boxed instance, but luckily the vcall
9828                                          * will be transformed into a normal call there.
9829                                          */
9830                                 } else if (context_used) {
9831                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9832                                         *sp = alloc;
9833                                 } else {
9834                                         MonoVTable *vtable = NULL;
9835
9836                                         if (!cfg->compile_aot)
9837                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9838                                         CHECK_TYPELOAD (cmethod->klass);
9839
9840                                         /*
9841                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9842                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9843                                          * As a workaround, we call class cctors before allocating objects.
9844                                          */
9845                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9846                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9847                                                 if (cfg->verbose_level > 2)
9848                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9849                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9850                                         }
9851
9852                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9853                                         *sp = alloc;
9854                                 }
9855                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9856
9857                                 if (alloc)
9858                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9859
9860                                 /* Now call the actual ctor */
9861                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
9862                                 CHECK_CFG_EXCEPTION;
9863                         }
9864
9865                         if (alloc == NULL) {
9866                                 /* Valuetype */
9867                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9868                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9869                                 *sp++= ins;
9870                         } else {
9871                                 *sp++ = alloc;
9872                         }
9873                         
9874                         ip += 5;
9875                         inline_costs += 5;
9876                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
9877                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9878                         break;
9879                 }
9880                 case CEE_CASTCLASS:
9881                         CHECK_STACK (1);
9882                         --sp;
9883                         CHECK_OPSIZE (5);
9884                         token = read32 (ip + 1);
9885                         klass = mini_get_class (method, token, generic_context);
9886                         CHECK_TYPELOAD (klass);
9887                         if (sp [0]->type != STACK_OBJ)
9888                                 UNVERIFIED;
9889
9890                         ins = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
9891                         CHECK_CFG_EXCEPTION;
9892
9893                         *sp ++ = ins;
9894                         ip += 5;
9895                         break;
9896                 case CEE_ISINST: {
9897                         CHECK_STACK (1);
9898                         --sp;
9899                         CHECK_OPSIZE (5);
9900                         token = read32 (ip + 1);
9901                         klass = mini_get_class (method, token, generic_context);
9902                         CHECK_TYPELOAD (klass);
9903                         if (sp [0]->type != STACK_OBJ)
9904                                 UNVERIFIED;
9905  
9906                         context_used = mini_class_check_context_used (cfg, klass);
9907
9908                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9909                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9910                                 MonoInst *args [3];
9911
9912                                 /* obj */
9913                                 args [0] = *sp;
9914
9915                                 /* klass */
9916                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9917
9918                                 /* inline cache*/
9919                                 if (cfg->compile_aot)
9920                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9921                                 else
9922                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9923
9924                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9925                                 ip += 5;
9926                                 inline_costs += 2;
9927                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9928                                 MonoMethod *mono_isinst;
9929                                 MonoInst *iargs [1];
9930                                 int costs;
9931
9932                                 mono_isinst = mono_marshal_get_isinst (klass); 
9933                                 iargs [0] = sp [0];
9934
9935                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9936                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
9937                                 CHECK_CFG_EXCEPTION;
9938                                 g_assert (costs > 0);
9939                                 
9940                                 ip += 5;
9941                                 cfg->real_offset += 5;
9942
9943                                 *sp++= iargs [0];
9944
9945                                 inline_costs += costs;
9946                         }
9947                         else {
9948                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9949                                 CHECK_CFG_EXCEPTION;
9950                                 bblock = cfg->cbb;
9951                                 *sp ++ = ins;
9952                                 ip += 5;
9953                         }
9954                         break;
9955                 }
9956                 case CEE_UNBOX_ANY: {
9957                         MonoInst *res, *addr;
9958
9959                         CHECK_STACK (1);
9960                         --sp;
9961                         CHECK_OPSIZE (5);
9962                         token = read32 (ip + 1);
9963                         klass = mini_get_class (method, token, generic_context);
9964                         CHECK_TYPELOAD (klass);
9965  
9966                         mono_save_token_info (cfg, image, token, klass);
9967
9968                         context_used = mini_class_check_context_used (cfg, klass);
9969
9970                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9971                                 res = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9972                                 inline_costs += 2;
9973                         } else if (generic_class_is_reference_type (cfg, klass)) {
9974                                 res = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
9975                                 CHECK_CFG_EXCEPTION;
9976                         } else if (mono_class_is_nullable (klass)) {
9977                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
9978                         } else {
9979                                 addr = handle_unbox (cfg, klass, sp, context_used);
9980                                 /* LDOBJ */
9981                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
9982                                 res = ins;
9983                                 inline_costs += 2;
9984                         }
9985
9986                         *sp ++ = res;
9987                         ip += 5;
9988                         break;
9989                 }
9990                 case CEE_BOX: {
9991                         MonoInst *val;
9992
9993                         CHECK_STACK (1);
9994                         --sp;
9995                         val = *sp;
9996                         CHECK_OPSIZE (5);
9997                         token = read32 (ip + 1);
9998                         klass = mini_get_class (method, token, generic_context);
9999                         CHECK_TYPELOAD (klass);
10000
10001                         mono_save_token_info (cfg, image, token, klass);
10002
10003                         context_used = mini_class_check_context_used (cfg, klass);
10004
10005                         if (generic_class_is_reference_type (cfg, klass)) {
10006                                 *sp++ = val;
10007                                 ip += 5;
10008                                 break;
10009                         }
10010
10011                         if (klass == mono_defaults.void_class)
10012                                 UNVERIFIED;
10013                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10014                                 UNVERIFIED;
10015                         /* frequent check in generic code: box (struct), brtrue */
10016
10017                         // FIXME: LLVM can't handle the inconsistent bb linking
10018                         if (!mono_class_is_nullable (klass) &&
10019                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
10020                                 (ip [5] == CEE_BRTRUE || 
10021                                  ip [5] == CEE_BRTRUE_S ||
10022                                  ip [5] == CEE_BRFALSE ||
10023                                  ip [5] == CEE_BRFALSE_S)) {
10024                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10025                                 int dreg;
10026                                 MonoBasicBlock *true_bb, *false_bb;
10027
10028                                 ip += 5;
10029
10030                                 if (cfg->verbose_level > 3) {
10031                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10032                                         printf ("<box+brtrue opt>\n");
10033                                 }
10034
10035                                 switch (*ip) {
10036                                 case CEE_BRTRUE_S:
10037                                 case CEE_BRFALSE_S:
10038                                         CHECK_OPSIZE (2);
10039                                         ip++;
10040                                         target = ip + 1 + (signed char)(*ip);
10041                                         ip++;
10042                                         break;
10043                                 case CEE_BRTRUE:
10044                                 case CEE_BRFALSE:
10045                                         CHECK_OPSIZE (5);
10046                                         ip++;
10047                                         target = ip + 4 + (gint)(read32 (ip));
10048                                         ip += 4;
10049                                         break;
10050                                 default:
10051                                         g_assert_not_reached ();
10052                                 }
10053
10054                                 /* 
10055                                  * We need to link both bblocks, since it is needed for handling stack
10056                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10057                                  * Branching to only one of them would lead to inconsistencies, so
10058                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10059                                  */
10060                                 GET_BBLOCK (cfg, true_bb, target);
10061                                 GET_BBLOCK (cfg, false_bb, ip);
10062
10063                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10064                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10065
10066                                 if (sp != stack_start) {
10067                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10068                                         sp = stack_start;
10069                                         CHECK_UNVERIFIABLE (cfg);
10070                                 }
10071
10072                                 if (COMPILE_LLVM (cfg)) {
10073                                         dreg = alloc_ireg (cfg);
10074                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10075                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10076
10077                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10078                                 } else {
10079                                         /* The JIT can't eliminate the iconst+compare */
10080                                         MONO_INST_NEW (cfg, ins, OP_BR);
10081                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10082                                         MONO_ADD_INS (cfg->cbb, ins);
10083                                 }
10084
10085                                 start_new_bblock = 1;
10086                                 break;
10087                         }
10088
10089                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10090
10091                         CHECK_CFG_EXCEPTION;
10092                         ip += 5;
10093                         inline_costs += 1;
10094                         break;
10095                 }
10096                 case CEE_UNBOX: {
10097                         CHECK_STACK (1);
10098                         --sp;
10099                         CHECK_OPSIZE (5);
10100                         token = read32 (ip + 1);
10101                         klass = mini_get_class (method, token, generic_context);
10102                         CHECK_TYPELOAD (klass);
10103
10104                         mono_save_token_info (cfg, image, token, klass);
10105
10106                         context_used = mini_class_check_context_used (cfg, klass);
10107
10108                         if (mono_class_is_nullable (klass)) {
10109                                 MonoInst *val;
10110
10111                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10112                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10113
10114                                 *sp++= ins;
10115                         } else {
10116                                 ins = handle_unbox (cfg, klass, sp, context_used);
10117                                 *sp++ = ins;
10118                         }
10119                         ip += 5;
10120                         inline_costs += 2;
10121                         break;
10122                 }
10123                 case CEE_LDFLD:
10124                 case CEE_LDFLDA:
10125                 case CEE_STFLD:
10126                 case CEE_LDSFLD:
10127                 case CEE_LDSFLDA:
10128                 case CEE_STSFLD: {
10129                         MonoClassField *field;
10130 #ifndef DISABLE_REMOTING
10131                         int costs;
10132 #endif
10133                         guint foffset;
10134                         gboolean is_instance;
10135                         int op;
10136                         gpointer addr = NULL;
10137                         gboolean is_special_static;
10138                         MonoType *ftype;
10139                         MonoInst *store_val = NULL;
10140                         MonoInst *thread_ins;
10141
10142                         op = *ip;
10143                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10144                         if (is_instance) {
10145                                 if (op == CEE_STFLD) {
10146                                         CHECK_STACK (2);
10147                                         sp -= 2;
10148                                         store_val = sp [1];
10149                                 } else {
10150                                         CHECK_STACK (1);
10151                                         --sp;
10152                                 }
10153                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10154                                         UNVERIFIED;
10155                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10156                                         UNVERIFIED;
10157                         } else {
10158                                 if (op == CEE_STSFLD) {
10159                                         CHECK_STACK (1);
10160                                         sp--;
10161                                         store_val = sp [0];
10162                                 }
10163                         }
10164
10165                         CHECK_OPSIZE (5);
10166                         token = read32 (ip + 1);
10167                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10168                                 field = mono_method_get_wrapper_data (method, token);
10169                                 klass = field->parent;
10170                         }
10171                         else {
10172                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10173                                 CHECK_CFG_ERROR;
10174                         }
10175                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10176                                 FIELD_ACCESS_FAILURE (method, field);
10177                         mono_class_init (klass);
10178
10179                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10180                                 UNVERIFIED;
10181
10182                         /* if the class is Critical then transparent code cannot access it's fields */
10183                         if (!is_instance && mono_security_core_clr_enabled ())
10184                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10185
10186                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10187                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10188                         if (mono_security_core_clr_enabled ())
10189                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10190                         */
10191
10192                         /*
10193                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10194                          * the static case.
10195                          */
10196                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10197                                 switch (op) {
10198                                 case CEE_LDFLD:
10199                                         op = CEE_LDSFLD;
10200                                         break;
10201                                 case CEE_STFLD:
10202                                         op = CEE_STSFLD;
10203                                         break;
10204                                 case CEE_LDFLDA:
10205                                         op = CEE_LDSFLDA;
10206                                         break;
10207                                 default:
10208                                         g_assert_not_reached ();
10209                                 }
10210                                 is_instance = FALSE;
10211                         }
10212
10213                         context_used = mini_class_check_context_used (cfg, klass);
10214
10215                         /* INSTANCE CASE */
10216
10217                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10218                         if (op == CEE_STFLD) {
10219                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10220                                         UNVERIFIED;
10221 #ifndef DISABLE_REMOTING
10222                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10223                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10224                                         MonoInst *iargs [5];
10225
10226                                         GSHAREDVT_FAILURE (op);
10227
10228                                         iargs [0] = sp [0];
10229                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10230                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10231                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10232                                                     field->offset);
10233                                         iargs [4] = sp [1];
10234
10235                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10236                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10237                                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10238                                                 CHECK_CFG_EXCEPTION;
10239                                                 g_assert (costs > 0);
10240                                                       
10241                                                 cfg->real_offset += 5;
10242
10243                                                 inline_costs += costs;
10244                                         } else {
10245                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10246                                         }
10247                                 } else
10248 #endif
10249                                 {
10250                                         MonoInst *store;
10251
10252                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10253
10254                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10255                                                 MonoInst *offset_ins;
10256
10257                                                 context_used = mini_class_check_context_used (cfg, klass);
10258
10259                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10260                                                 dreg = alloc_ireg_mp (cfg);
10261                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10262                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10263                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10264                                         } else {
10265                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10266                                         }
10267                                         if (sp [0]->opcode != OP_LDADDR)
10268                                                 store->flags |= MONO_INST_FAULT;
10269
10270                                 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)) {
10271                                         /* insert call to write barrier */
10272                                         MonoInst *ptr;
10273                                         int dreg;
10274
10275                                         dreg = alloc_ireg_mp (cfg);
10276                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10277                                         emit_write_barrier (cfg, ptr, sp [1]);
10278                                 }
10279
10280                                         store->flags |= ins_flag;
10281                                 }
10282                                 ins_flag = 0;
10283                                 ip += 5;
10284                                 break;
10285                         }
10286
10287 #ifndef DISABLE_REMOTING
10288                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10289                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10290                                 MonoInst *iargs [4];
10291
10292                                 GSHAREDVT_FAILURE (op);
10293
10294                                 iargs [0] = sp [0];
10295                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10296                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10297                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10298                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10299                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10300                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
10301                                         CHECK_CFG_EXCEPTION;
10302                                         g_assert (costs > 0);
10303                                                       
10304                                         cfg->real_offset += 5;
10305
10306                                         *sp++ = iargs [0];
10307
10308                                         inline_costs += costs;
10309                                 } else {
10310                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10311                                         *sp++ = ins;
10312                                 }
10313                         } else 
10314 #endif
10315                         if (is_instance) {
10316                                 if (sp [0]->type == STACK_VTYPE) {
10317                                         MonoInst *var;
10318
10319                                         /* Have to compute the address of the variable */
10320
10321                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10322                                         if (!var)
10323                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10324                                         else
10325                                                 g_assert (var->klass == klass);
10326                                         
10327                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10328                                         sp [0] = ins;
10329                                 }
10330
10331                                 if (op == CEE_LDFLDA) {
10332                                         if (is_magic_tls_access (field)) {
10333                                                 GSHAREDVT_FAILURE (*ip);
10334                                                 ins = sp [0];
10335                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10336                                         } else {
10337                                                 if (sp [0]->type == STACK_OBJ) {
10338                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10339                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10340                                                 }
10341
10342                                                 dreg = alloc_ireg_mp (cfg);
10343
10344                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10345                                                         MonoInst *offset_ins;
10346
10347                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10348                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10349                                                 } else {
10350                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10351                                                 }
10352                                                 ins->klass = mono_class_from_mono_type (field->type);
10353                                                 ins->type = STACK_MP;
10354                                                 *sp++ = ins;
10355                                         }
10356                                 } else {
10357                                         MonoInst *load;
10358
10359                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10360
10361                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10362                                                 MonoInst *offset_ins;
10363
10364                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10365                                                 dreg = alloc_ireg_mp (cfg);
10366                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10367                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10368                                         } else {
10369                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10370                                         }
10371                                         load->flags |= ins_flag;
10372                                         if (sp [0]->opcode != OP_LDADDR)
10373                                                 load->flags |= MONO_INST_FAULT;
10374                                         *sp++ = load;
10375                                 }
10376                         }
10377
10378                         if (is_instance) {
10379                                 ins_flag = 0;
10380                                 ip += 5;
10381                                 break;
10382                         }
10383
10384                         /* STATIC CASE */
10385
10386                         /*
10387                          * We can only support shared generic static
10388                          * field access on architectures where the
10389                          * trampoline code has been extended to handle
10390                          * the generic class init.
10391                          */
10392 #ifndef MONO_ARCH_VTABLE_REG
10393                         GENERIC_SHARING_FAILURE (op);
10394 #endif
10395
10396                         context_used = mini_class_check_context_used (cfg, klass);
10397
10398                         ftype = mono_field_get_type (field);
10399
10400                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10401                                 UNVERIFIED;
10402
10403                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10404                          * to be called here.
10405                          */
10406                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10407                                 mono_class_vtable (cfg->domain, klass);
10408                                 CHECK_TYPELOAD (klass);
10409                         }
10410                         mono_domain_lock (cfg->domain);
10411                         if (cfg->domain->special_static_fields)
10412                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10413                         mono_domain_unlock (cfg->domain);
10414
10415                         is_special_static = mono_class_field_is_special_static (field);
10416
10417                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10418                                 thread_ins = mono_get_thread_intrinsic (cfg);
10419                         else
10420                                 thread_ins = NULL;
10421
10422                         /* Generate IR to compute the field address */
10423                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10424                                 /*
10425                                  * Fast access to TLS data
10426                                  * Inline version of get_thread_static_data () in
10427                                  * threads.c.
10428                                  */
10429                                 guint32 offset;
10430                                 int idx, static_data_reg, array_reg, dreg;
10431
10432                                 GSHAREDVT_FAILURE (op);
10433
10434                                 // offset &= 0x7fffffff;
10435                                 // idx = (offset >> 24) - 1;
10436                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10437                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10438                                 static_data_reg = alloc_ireg (cfg);
10439                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10440
10441                                 if (cfg->compile_aot) {
10442                                         int offset_reg, offset2_reg, idx_reg;
10443
10444                                         /* For TLS variables, this will return the TLS offset */
10445                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10446                                         offset_reg = ins->dreg;
10447                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10448                                         idx_reg = alloc_ireg (cfg);
10449                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10450                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10451                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10452                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10453                                         array_reg = alloc_ireg (cfg);
10454                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10455                                         offset2_reg = alloc_ireg (cfg);
10456                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10457                                         dreg = alloc_ireg (cfg);
10458                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10459                                 } else {
10460                                         offset = (gsize)addr & 0x7fffffff;
10461                                         idx = (offset >> 24) - 1;
10462
10463                                         array_reg = alloc_ireg (cfg);
10464                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10465                                         dreg = alloc_ireg (cfg);
10466                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10467                                 }
10468                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10469                                         (cfg->compile_aot && is_special_static) ||
10470                                         (context_used && is_special_static)) {
10471                                 MonoInst *iargs [2];
10472
10473                                 g_assert (field->parent);
10474                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10475                                 if (context_used) {
10476                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10477                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10478                                 } else {
10479                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10480                                 }
10481                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10482                         } else if (context_used) {
10483                                 MonoInst *static_data;
10484
10485                                 /*
10486                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10487                                         method->klass->name_space, method->klass->name, method->name,
10488                                         depth, field->offset);
10489                                 */
10490
10491                                 if (mono_class_needs_cctor_run (klass, method))
10492                                         emit_generic_class_init (cfg, klass);
10493
10494                                 /*
10495                                  * The pointer we're computing here is
10496                                  *
10497                                  *   super_info.static_data + field->offset
10498                                  */
10499                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10500                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10501
10502                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10503                                         MonoInst *offset_ins;
10504
10505                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10506                                         dreg = alloc_ireg_mp (cfg);
10507                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10508                                 } else if (field->offset == 0) {
10509                                         ins = static_data;
10510                                 } else {
10511                                         int addr_reg = mono_alloc_preg (cfg);
10512                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10513                                 }
10514                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10515                                 MonoInst *iargs [2];
10516
10517                                 g_assert (field->parent);
10518                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10519                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10520                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10521                         } else {
10522                                 MonoVTable *vtable = NULL;
10523
10524                                 if (!cfg->compile_aot)
10525                                         vtable = mono_class_vtable (cfg->domain, klass);
10526                                 CHECK_TYPELOAD (klass);
10527
10528                                 if (!addr) {
10529                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10530                                                 if (!(g_slist_find (class_inits, klass))) {
10531                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10532                                                         if (cfg->verbose_level > 2)
10533                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10534                                                         class_inits = g_slist_prepend (class_inits, klass);
10535                                                 }
10536                                         } else {
10537                                                 if (cfg->run_cctors) {
10538                                                         MonoException *ex;
10539                                                         /* This makes so that inline cannot trigger */
10540                                                         /* .cctors: too many apps depend on them */
10541                                                         /* running with a specific order... */
10542                                                         g_assert (vtable);
10543                                                         if (! vtable->initialized)
10544                                                                 INLINE_FAILURE ("class init");
10545                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10546                                                         if (ex) {
10547                                                                 set_exception_object (cfg, ex);
10548                                                                 goto exception_exit;
10549                                                         }
10550                                                 }
10551                                         }
10552                                         if (cfg->compile_aot)
10553                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10554                                         else {
10555                                                 g_assert (vtable);
10556                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10557                                                 g_assert (addr);
10558                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10559                                         }
10560                                 } else {
10561                                         MonoInst *iargs [1];
10562                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10563                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10564                                 }
10565                         }
10566
10567                         /* Generate IR to do the actual load/store operation */
10568
10569                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10570                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10571                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10572                                 emit_memory_barrier (cfg, FullBarrier);
10573                         }
10574
10575                         if (op == CEE_LDSFLDA) {
10576                                 ins->klass = mono_class_from_mono_type (ftype);
10577                                 ins->type = STACK_PTR;
10578                                 *sp++ = ins;
10579                         } else if (op == CEE_STSFLD) {
10580                                 MonoInst *store;
10581
10582                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10583                                 store->flags |= ins_flag;
10584                         } else {
10585                                 gboolean is_const = FALSE;
10586                                 MonoVTable *vtable = NULL;
10587                                 gpointer addr = NULL;
10588
10589                                 if (!context_used) {
10590                                         vtable = mono_class_vtable (cfg->domain, klass);
10591                                         CHECK_TYPELOAD (klass);
10592                                 }
10593                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10594                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10595                                         int ro_type = ftype->type;
10596                                         if (!addr)
10597                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10598                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10599                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10600                                         }
10601
10602                                         GSHAREDVT_FAILURE (op);
10603
10604                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10605                                         is_const = TRUE;
10606                                         switch (ro_type) {
10607                                         case MONO_TYPE_BOOLEAN:
10608                                         case MONO_TYPE_U1:
10609                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10610                                                 sp++;
10611                                                 break;
10612                                         case MONO_TYPE_I1:
10613                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10614                                                 sp++;
10615                                                 break;                                          
10616                                         case MONO_TYPE_CHAR:
10617                                         case MONO_TYPE_U2:
10618                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10619                                                 sp++;
10620                                                 break;
10621                                         case MONO_TYPE_I2:
10622                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10623                                                 sp++;
10624                                                 break;
10625                                                 break;
10626                                         case MONO_TYPE_I4:
10627                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10628                                                 sp++;
10629                                                 break;                                          
10630                                         case MONO_TYPE_U4:
10631                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10632                                                 sp++;
10633                                                 break;
10634                                         case MONO_TYPE_I:
10635                                         case MONO_TYPE_U:
10636                                         case MONO_TYPE_PTR:
10637                                         case MONO_TYPE_FNPTR:
10638                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10639                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10640                                                 sp++;
10641                                                 break;
10642                                         case MONO_TYPE_STRING:
10643                                         case MONO_TYPE_OBJECT:
10644                                         case MONO_TYPE_CLASS:
10645                                         case MONO_TYPE_SZARRAY:
10646                                         case MONO_TYPE_ARRAY:
10647                                                 if (!mono_gc_is_moving ()) {
10648                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10649                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10650                                                         sp++;
10651                                                 } else {
10652                                                         is_const = FALSE;
10653                                                 }
10654                                                 break;
10655                                         case MONO_TYPE_I8:
10656                                         case MONO_TYPE_U8:
10657                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10658                                                 sp++;
10659                                                 break;
10660                                         case MONO_TYPE_R4:
10661                                         case MONO_TYPE_R8:
10662                                         case MONO_TYPE_VALUETYPE:
10663                                         default:
10664                                                 is_const = FALSE;
10665                                                 break;
10666                                         }
10667                                 }
10668
10669                                 if (!is_const) {
10670                                         MonoInst *load;
10671
10672                                         CHECK_STACK_OVF (1);
10673
10674                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10675                                         load->flags |= ins_flag;
10676                                         ins_flag = 0;
10677                                         *sp++ = load;
10678                                 }
10679                         }
10680
10681                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10682                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10683                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10684                                 emit_memory_barrier (cfg, FullBarrier);
10685                         }
10686
10687                         ins_flag = 0;
10688                         ip += 5;
10689                         break;
10690                 }
10691                 case CEE_STOBJ:
10692                         CHECK_STACK (2);
10693                         sp -= 2;
10694                         CHECK_OPSIZE (5);
10695                         token = read32 (ip + 1);
10696                         klass = mini_get_class (method, token, generic_context);
10697                         CHECK_TYPELOAD (klass);
10698                         if (ins_flag & MONO_INST_VOLATILE) {
10699                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10700                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
10701                                 emit_memory_barrier (cfg, FullBarrier);
10702                         }
10703                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10704                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10705                         ins->flags |= ins_flag;
10706                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10707                                         generic_class_is_reference_type (cfg, klass)) {
10708                                 /* insert call to write barrier */
10709                                 emit_write_barrier (cfg, sp [0], sp [1]);
10710                         }
10711                         ins_flag = 0;
10712                         ip += 5;
10713                         inline_costs += 1;
10714                         break;
10715
10716                         /*
10717                          * Array opcodes
10718                          */
10719                 case CEE_NEWARR: {
10720                         MonoInst *len_ins;
10721                         const char *data_ptr;
10722                         int data_size = 0;
10723                         guint32 field_token;
10724
10725                         CHECK_STACK (1);
10726                         --sp;
10727
10728                         CHECK_OPSIZE (5);
10729                         token = read32 (ip + 1);
10730
10731                         klass = mini_get_class (method, token, generic_context);
10732                         CHECK_TYPELOAD (klass);
10733
10734                         context_used = mini_class_check_context_used (cfg, klass);
10735
10736                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10737                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10738                                 ins->sreg1 = sp [0]->dreg;
10739                                 ins->type = STACK_I4;
10740                                 ins->dreg = alloc_ireg (cfg);
10741                                 MONO_ADD_INS (cfg->cbb, ins);
10742                                 *sp = mono_decompose_opcode (cfg, ins);
10743                         }
10744
10745                         if (context_used) {
10746                                 MonoInst *args [3];
10747                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10748                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10749
10750                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10751
10752                                 /* vtable */
10753                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10754                                         array_class, MONO_RGCTX_INFO_VTABLE);
10755                                 /* array len */
10756                                 args [1] = sp [0];
10757
10758                                 if (managed_alloc)
10759                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10760                                 else
10761                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10762                         } else {
10763                                 if (cfg->opt & MONO_OPT_SHARED) {
10764                                         /* Decompose now to avoid problems with references to the domainvar */
10765                                         MonoInst *iargs [3];
10766
10767                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10768                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10769                                         iargs [2] = sp [0];
10770
10771                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10772                                 } else {
10773                                         /* Decompose later since it is needed by abcrem */
10774                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10775                                         mono_class_vtable (cfg->domain, array_type);
10776                                         CHECK_TYPELOAD (array_type);
10777
10778                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10779                                         ins->dreg = alloc_ireg_ref (cfg);
10780                                         ins->sreg1 = sp [0]->dreg;
10781                                         ins->inst_newa_class = klass;
10782                                         ins->type = STACK_OBJ;
10783                                         ins->klass = array_type;
10784                                         MONO_ADD_INS (cfg->cbb, ins);
10785                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10786                                         cfg->cbb->has_array_access = TRUE;
10787
10788                                         /* Needed so mono_emit_load_get_addr () gets called */
10789                                         mono_get_got_var (cfg);
10790                                 }
10791                         }
10792
10793                         len_ins = sp [0];
10794                         ip += 5;
10795                         *sp++ = ins;
10796                         inline_costs += 1;
10797
10798                         /* 
10799                          * we inline/optimize the initialization sequence if possible.
10800                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10801                          * for small sizes open code the memcpy
10802                          * ensure the rva field is big enough
10803                          */
10804                         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))) {
10805                                 MonoMethod *memcpy_method = get_memcpy_method ();
10806                                 MonoInst *iargs [3];
10807                                 int add_reg = alloc_ireg_mp (cfg);
10808
10809                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
10810                                 if (cfg->compile_aot) {
10811                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10812                                 } else {
10813                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10814                                 }
10815                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10816                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10817                                 ip += 11;
10818                         }
10819
10820                         break;
10821                 }
10822                 case CEE_LDLEN:
10823                         CHECK_STACK (1);
10824                         --sp;
10825                         if (sp [0]->type != STACK_OBJ)
10826                                 UNVERIFIED;
10827
10828                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10829                         ins->dreg = alloc_preg (cfg);
10830                         ins->sreg1 = sp [0]->dreg;
10831                         ins->type = STACK_I4;
10832                         /* This flag will be inherited by the decomposition */
10833                         ins->flags |= MONO_INST_FAULT;
10834                         MONO_ADD_INS (cfg->cbb, ins);
10835                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10836                         cfg->cbb->has_array_access = TRUE;
10837                         ip ++;
10838                         *sp++ = ins;
10839                         break;
10840                 case CEE_LDELEMA:
10841                         CHECK_STACK (2);
10842                         sp -= 2;
10843                         CHECK_OPSIZE (5);
10844                         if (sp [0]->type != STACK_OBJ)
10845                                 UNVERIFIED;
10846
10847                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10848
10849                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10850                         CHECK_TYPELOAD (klass);
10851                         /* we need to make sure that this array is exactly the type it needs
10852                          * to be for correctness. the wrappers are lax with their usage
10853                          * so we need to ignore them here
10854                          */
10855                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10856                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10857                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10858                                 CHECK_TYPELOAD (array_class);
10859                         }
10860
10861                         readonly = FALSE;
10862                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10863                         *sp++ = ins;
10864                         ip += 5;
10865                         break;
10866                 case CEE_LDELEM:
10867                 case CEE_LDELEM_I1:
10868                 case CEE_LDELEM_U1:
10869                 case CEE_LDELEM_I2:
10870                 case CEE_LDELEM_U2:
10871                 case CEE_LDELEM_I4:
10872                 case CEE_LDELEM_U4:
10873                 case CEE_LDELEM_I8:
10874                 case CEE_LDELEM_I:
10875                 case CEE_LDELEM_R4:
10876                 case CEE_LDELEM_R8:
10877                 case CEE_LDELEM_REF: {
10878                         MonoInst *addr;
10879
10880                         CHECK_STACK (2);
10881                         sp -= 2;
10882
10883                         if (*ip == CEE_LDELEM) {
10884                                 CHECK_OPSIZE (5);
10885                                 token = read32 (ip + 1);
10886                                 klass = mini_get_class (method, token, generic_context);
10887                                 CHECK_TYPELOAD (klass);
10888                                 mono_class_init (klass);
10889                         }
10890                         else
10891                                 klass = array_access_to_klass (*ip);
10892
10893                         if (sp [0]->type != STACK_OBJ)
10894                                 UNVERIFIED;
10895
10896                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10897
10898                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
10899                                 // FIXME-VT: OP_ICONST optimization
10900                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10901                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10902                                 ins->opcode = OP_LOADV_MEMBASE;
10903                         } else if (sp [1]->opcode == OP_ICONST) {
10904                                 int array_reg = sp [0]->dreg;
10905                                 int index_reg = sp [1]->dreg;
10906                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
10907
10908                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10909                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10910                         } else {
10911                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10912                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10913                         }
10914                         *sp++ = ins;
10915                         if (*ip == CEE_LDELEM)
10916                                 ip += 5;
10917                         else
10918                                 ++ip;
10919                         break;
10920                 }
10921                 case CEE_STELEM_I:
10922                 case CEE_STELEM_I1:
10923                 case CEE_STELEM_I2:
10924                 case CEE_STELEM_I4:
10925                 case CEE_STELEM_I8:
10926                 case CEE_STELEM_R4:
10927                 case CEE_STELEM_R8:
10928                 case CEE_STELEM_REF:
10929                 case CEE_STELEM: {
10930                         CHECK_STACK (3);
10931                         sp -= 3;
10932
10933                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10934
10935                         if (*ip == CEE_STELEM) {
10936                                 CHECK_OPSIZE (5);
10937                                 token = read32 (ip + 1);
10938                                 klass = mini_get_class (method, token, generic_context);
10939                                 CHECK_TYPELOAD (klass);
10940                                 mono_class_init (klass);
10941                         }
10942                         else
10943                                 klass = array_access_to_klass (*ip);
10944
10945                         if (sp [0]->type != STACK_OBJ)
10946                                 UNVERIFIED;
10947
10948                         emit_array_store (cfg, klass, sp, TRUE);
10949
10950                         if (*ip == CEE_STELEM)
10951                                 ip += 5;
10952                         else
10953                                 ++ip;
10954                         inline_costs += 1;
10955                         break;
10956                 }
10957                 case CEE_CKFINITE: {
10958                         CHECK_STACK (1);
10959                         --sp;
10960
10961                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10962                         ins->sreg1 = sp [0]->dreg;
10963                         ins->dreg = alloc_freg (cfg);
10964                         ins->type = STACK_R8;
10965                         MONO_ADD_INS (bblock, ins);
10966
10967                         *sp++ = mono_decompose_opcode (cfg, ins);
10968
10969                         ++ip;
10970                         break;
10971                 }
10972                 case CEE_REFANYVAL: {
10973                         MonoInst *src_var, *src;
10974
10975                         int klass_reg = alloc_preg (cfg);
10976                         int dreg = alloc_preg (cfg);
10977
10978                         GSHAREDVT_FAILURE (*ip);
10979
10980                         CHECK_STACK (1);
10981                         MONO_INST_NEW (cfg, ins, *ip);
10982                         --sp;
10983                         CHECK_OPSIZE (5);
10984                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10985                         CHECK_TYPELOAD (klass);
10986
10987                         context_used = mini_class_check_context_used (cfg, klass);
10988
10989                         // FIXME:
10990                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10991                         if (!src_var)
10992                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10993                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10994                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
10995
10996                         if (context_used) {
10997                                 MonoInst *klass_ins;
10998
10999                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11000                                                 klass, MONO_RGCTX_INFO_KLASS);
11001
11002                                 // FIXME:
11003                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11004                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11005                         } else {
11006                                 mini_emit_class_check (cfg, klass_reg, klass);
11007                         }
11008                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11009                         ins->type = STACK_MP;
11010                         *sp++ = ins;
11011                         ip += 5;
11012                         break;
11013                 }
11014                 case CEE_MKREFANY: {
11015                         MonoInst *loc, *addr;
11016
11017                         GSHAREDVT_FAILURE (*ip);
11018
11019                         CHECK_STACK (1);
11020                         MONO_INST_NEW (cfg, ins, *ip);
11021                         --sp;
11022                         CHECK_OPSIZE (5);
11023                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11024                         CHECK_TYPELOAD (klass);
11025
11026                         context_used = mini_class_check_context_used (cfg, klass);
11027
11028                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11029                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11030
11031                         if (context_used) {
11032                                 MonoInst *const_ins;
11033                                 int type_reg = alloc_preg (cfg);
11034
11035                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11036                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11037                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11038                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11039                         } else if (cfg->compile_aot) {
11040                                 int const_reg = alloc_preg (cfg);
11041                                 int type_reg = alloc_preg (cfg);
11042
11043                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11044                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11045                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11046                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11047                         } else {
11048                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11049                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11050                         }
11051                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11052
11053                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11054                         ins->type = STACK_VTYPE;
11055                         ins->klass = mono_defaults.typed_reference_class;
11056                         *sp++ = ins;
11057                         ip += 5;
11058                         break;
11059                 }
11060                 case CEE_LDTOKEN: {
11061                         gpointer handle;
11062                         MonoClass *handle_class;
11063
11064                         CHECK_STACK_OVF (1);
11065
11066                         CHECK_OPSIZE (5);
11067                         n = read32 (ip + 1);
11068
11069                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11070                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11071                                 handle = mono_method_get_wrapper_data (method, n);
11072                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11073                                 if (handle_class == mono_defaults.typehandle_class)
11074                                         handle = &((MonoClass*)handle)->byval_arg;
11075                         }
11076                         else {
11077                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11078                                 CHECK_CFG_ERROR;
11079                         }
11080                         if (!handle)
11081                                 LOAD_ERROR;
11082                         mono_class_init (handle_class);
11083                         if (cfg->generic_sharing_context) {
11084                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11085                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11086                                         /* This case handles ldtoken
11087                                            of an open type, like for
11088                                            typeof(Gen<>). */
11089                                         context_used = 0;
11090                                 } else if (handle_class == mono_defaults.typehandle_class) {
11091                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11092                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11093                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11094                                 else if (handle_class == mono_defaults.methodhandle_class)
11095                                         context_used = mini_method_check_context_used (cfg, handle);
11096                                 else
11097                                         g_assert_not_reached ();
11098                         }
11099
11100                         if ((cfg->opt & MONO_OPT_SHARED) &&
11101                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11102                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11103                                 MonoInst *addr, *vtvar, *iargs [3];
11104                                 int method_context_used;
11105
11106                                 method_context_used = mini_method_check_context_used (cfg, method);
11107
11108                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11109
11110                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11111                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11112                                 if (method_context_used) {
11113                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11114                                                 method, MONO_RGCTX_INFO_METHOD);
11115                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11116                                 } else {
11117                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11118                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11119                                 }
11120                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11121
11122                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11123
11124                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11125                         } else {
11126                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11127                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11128                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11129                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11130                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11131                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11132
11133                                         mono_class_init (tclass);
11134                                         if (context_used) {
11135                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11136                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11137                                         } else if (cfg->compile_aot) {
11138                                                 if (method->wrapper_type) {
11139                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11140                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11141                                                                 /* Special case for static synchronized wrappers */
11142                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11143                                                         } else {
11144                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11145                                                                 /* FIXME: n is not a normal token */
11146                                                                 DISABLE_AOT (cfg);
11147                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11148                                                         }
11149                                                 } else {
11150                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11151                                                 }
11152                                         } else {
11153                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11154                                         }
11155                                         ins->type = STACK_OBJ;
11156                                         ins->klass = cmethod->klass;
11157                                         ip += 5;
11158                                 } else {
11159                                         MonoInst *addr, *vtvar;
11160
11161                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11162
11163                                         if (context_used) {
11164                                                 if (handle_class == mono_defaults.typehandle_class) {
11165                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11166                                                                         mono_class_from_mono_type (handle),
11167                                                                         MONO_RGCTX_INFO_TYPE);
11168                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11169                                                         ins = emit_get_rgctx_method (cfg, context_used,
11170                                                                         handle, MONO_RGCTX_INFO_METHOD);
11171                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11172                                                         ins = emit_get_rgctx_field (cfg, context_used,
11173                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11174                                                 } else {
11175                                                         g_assert_not_reached ();
11176                                                 }
11177                                         } else if (cfg->compile_aot) {
11178                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11179                                         } else {
11180                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11181                                         }
11182                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11183                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11184                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11185                                 }
11186                         }
11187
11188                         *sp++ = ins;
11189                         ip += 5;
11190                         break;
11191                 }
11192                 case CEE_THROW:
11193                         CHECK_STACK (1);
11194                         MONO_INST_NEW (cfg, ins, OP_THROW);
11195                         --sp;
11196                         ins->sreg1 = sp [0]->dreg;
11197                         ip++;
11198                         bblock->out_of_line = TRUE;
11199                         MONO_ADD_INS (bblock, ins);
11200                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11201                         MONO_ADD_INS (bblock, ins);
11202                         sp = stack_start;
11203                         
11204                         link_bblock (cfg, bblock, end_bblock);
11205                         start_new_bblock = 1;
11206                         break;
11207                 case CEE_ENDFINALLY:
11208                         /* mono_save_seq_point_info () depends on this */
11209                         if (sp != stack_start)
11210                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11211                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11212                         MONO_ADD_INS (bblock, ins);
11213                         ip++;
11214                         start_new_bblock = 1;
11215
11216                         /*
11217                          * Control will leave the method so empty the stack, otherwise
11218                          * the next basic block will start with a nonempty stack.
11219                          */
11220                         while (sp != stack_start) {
11221                                 sp--;
11222                         }
11223                         break;
11224                 case CEE_LEAVE:
11225                 case CEE_LEAVE_S: {
11226                         GList *handlers;
11227
11228                         if (*ip == CEE_LEAVE) {
11229                                 CHECK_OPSIZE (5);
11230                                 target = ip + 5 + (gint32)read32(ip + 1);
11231                         } else {
11232                                 CHECK_OPSIZE (2);
11233                                 target = ip + 2 + (signed char)(ip [1]);
11234                         }
11235
11236                         /* empty the stack */
11237                         while (sp != stack_start) {
11238                                 sp--;
11239                         }
11240
11241                         /* 
11242                          * If this leave statement is in a catch block, check for a
11243                          * pending exception, and rethrow it if necessary.
11244                          * We avoid doing this in runtime invoke wrappers, since those are called
11245                          * by native code which excepts the wrapper to catch all exceptions.
11246                          */
11247                         for (i = 0; i < header->num_clauses; ++i) {
11248                                 MonoExceptionClause *clause = &header->clauses [i];
11249
11250                                 /* 
11251                                  * Use <= in the final comparison to handle clauses with multiple
11252                                  * leave statements, like in bug #78024.
11253                                  * The ordering of the exception clauses guarantees that we find the
11254                                  * innermost clause.
11255                                  */
11256                                 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) {
11257                                         MonoInst *exc_ins;
11258                                         MonoBasicBlock *dont_throw;
11259
11260                                         /*
11261                                           MonoInst *load;
11262
11263                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11264                                         */
11265
11266                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11267
11268                                         NEW_BBLOCK (cfg, dont_throw);
11269
11270                                         /*
11271                                          * Currently, we always rethrow the abort exception, despite the 
11272                                          * fact that this is not correct. See thread6.cs for an example. 
11273                                          * But propagating the abort exception is more important than 
11274                                          * getting the sematics right.
11275                                          */
11276                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11277                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11278                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11279
11280                                         MONO_START_BB (cfg, dont_throw);
11281                                         bblock = cfg->cbb;
11282                                 }
11283                         }
11284
11285                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11286                                 GList *tmp;
11287                                 MonoExceptionClause *clause;
11288
11289                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11290                                         clause = tmp->data;
11291                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11292                                         g_assert (tblock);
11293                                         link_bblock (cfg, bblock, tblock);
11294                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11295                                         ins->inst_target_bb = tblock;
11296                                         ins->inst_eh_block = clause;
11297                                         MONO_ADD_INS (bblock, ins);
11298                                         bblock->has_call_handler = 1;
11299                                         if (COMPILE_LLVM (cfg)) {
11300                                                 MonoBasicBlock *target_bb;
11301
11302                                                 /* 
11303                                                  * Link the finally bblock with the target, since it will
11304                                                  * conceptually branch there.
11305                                                  * FIXME: Have to link the bblock containing the endfinally.
11306                                                  */
11307                                                 GET_BBLOCK (cfg, target_bb, target);
11308                                                 link_bblock (cfg, tblock, target_bb);
11309                                         }
11310                                 }
11311                                 g_list_free (handlers);
11312                         } 
11313
11314                         MONO_INST_NEW (cfg, ins, OP_BR);
11315                         MONO_ADD_INS (bblock, ins);
11316                         GET_BBLOCK (cfg, tblock, target);
11317                         link_bblock (cfg, bblock, tblock);
11318                         ins->inst_target_bb = tblock;
11319                         start_new_bblock = 1;
11320
11321                         if (*ip == CEE_LEAVE)
11322                                 ip += 5;
11323                         else
11324                                 ip += 2;
11325
11326                         break;
11327                 }
11328
11329                         /*
11330                          * Mono specific opcodes
11331                          */
11332                 case MONO_CUSTOM_PREFIX: {
11333
11334                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11335
11336                         CHECK_OPSIZE (2);
11337                         switch (ip [1]) {
11338                         case CEE_MONO_ICALL: {
11339                                 gpointer func;
11340                                 MonoJitICallInfo *info;
11341
11342                                 token = read32 (ip + 2);
11343                                 func = mono_method_get_wrapper_data (method, token);
11344                                 info = mono_find_jit_icall_by_addr (func);
11345                                 if (!info)
11346                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11347                                 g_assert (info);
11348
11349                                 CHECK_STACK (info->sig->param_count);
11350                                 sp -= info->sig->param_count;
11351
11352                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11353                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11354                                         *sp++ = ins;
11355
11356                                 ip += 6;
11357                                 inline_costs += 10 * num_calls++;
11358
11359                                 break;
11360                         }
11361                         case CEE_MONO_LDPTR: {
11362                                 gpointer ptr;
11363
11364                                 CHECK_STACK_OVF (1);
11365                                 CHECK_OPSIZE (6);
11366                                 token = read32 (ip + 2);
11367
11368                                 ptr = mono_method_get_wrapper_data (method, token);
11369                                 /* FIXME: Generalize this */
11370                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11371                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11372                                         *sp++ = ins;
11373                                         ip += 6;
11374                                         break;
11375                                 }
11376                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11377                                 *sp++ = ins;
11378                                 ip += 6;
11379                                 inline_costs += 10 * num_calls++;
11380                                 /* Can't embed random pointers into AOT code */
11381                                 DISABLE_AOT (cfg);
11382                                 break;
11383                         }
11384                         case CEE_MONO_JIT_ICALL_ADDR: {
11385                                 MonoJitICallInfo *callinfo;
11386                                 gpointer ptr;
11387
11388                                 CHECK_STACK_OVF (1);
11389                                 CHECK_OPSIZE (6);
11390                                 token = read32 (ip + 2);
11391
11392                                 ptr = mono_method_get_wrapper_data (method, token);
11393                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11394                                 g_assert (callinfo);
11395                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11396                                 *sp++ = ins;
11397                                 ip += 6;
11398                                 inline_costs += 10 * num_calls++;
11399                                 break;
11400                         }
11401                         case CEE_MONO_ICALL_ADDR: {
11402                                 MonoMethod *cmethod;
11403                                 gpointer ptr;
11404
11405                                 CHECK_STACK_OVF (1);
11406                                 CHECK_OPSIZE (6);
11407                                 token = read32 (ip + 2);
11408
11409                                 cmethod = mono_method_get_wrapper_data (method, token);
11410
11411                                 if (cfg->compile_aot) {
11412                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11413                                 } else {
11414                                         ptr = mono_lookup_internal_call (cmethod);
11415                                         g_assert (ptr);
11416                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11417                                 }
11418                                 *sp++ = ins;
11419                                 ip += 6;
11420                                 break;
11421                         }
11422                         case CEE_MONO_VTADDR: {
11423                                 MonoInst *src_var, *src;
11424
11425                                 CHECK_STACK (1);
11426                                 --sp;
11427
11428                                 // FIXME:
11429                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11430                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11431                                 *sp++ = src;
11432                                 ip += 2;
11433                                 break;
11434                         }
11435                         case CEE_MONO_NEWOBJ: {
11436                                 MonoInst *iargs [2];
11437
11438                                 CHECK_STACK_OVF (1);
11439                                 CHECK_OPSIZE (6);
11440                                 token = read32 (ip + 2);
11441                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11442                                 mono_class_init (klass);
11443                                 NEW_DOMAINCONST (cfg, iargs [0]);
11444                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11445                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11446                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11447                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11448                                 ip += 6;
11449                                 inline_costs += 10 * num_calls++;
11450                                 break;
11451                         }
11452                         case CEE_MONO_OBJADDR:
11453                                 CHECK_STACK (1);
11454                                 --sp;
11455                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11456                                 ins->dreg = alloc_ireg_mp (cfg);
11457                                 ins->sreg1 = sp [0]->dreg;
11458                                 ins->type = STACK_MP;
11459                                 MONO_ADD_INS (cfg->cbb, ins);
11460                                 *sp++ = ins;
11461                                 ip += 2;
11462                                 break;
11463                         case CEE_MONO_LDNATIVEOBJ:
11464                                 /*
11465                                  * Similar to LDOBJ, but instead load the unmanaged 
11466                                  * representation of the vtype to the stack.
11467                                  */
11468                                 CHECK_STACK (1);
11469                                 CHECK_OPSIZE (6);
11470                                 --sp;
11471                                 token = read32 (ip + 2);
11472                                 klass = mono_method_get_wrapper_data (method, token);
11473                                 g_assert (klass->valuetype);
11474                                 mono_class_init (klass);
11475
11476                                 {
11477                                         MonoInst *src, *dest, *temp;
11478
11479                                         src = sp [0];
11480                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11481                                         temp->backend.is_pinvoke = 1;
11482                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11483                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11484
11485                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11486                                         dest->type = STACK_VTYPE;
11487                                         dest->klass = klass;
11488
11489                                         *sp ++ = dest;
11490                                         ip += 6;
11491                                 }
11492                                 break;
11493                         case CEE_MONO_RETOBJ: {
11494                                 /*
11495                                  * Same as RET, but return the native representation of a vtype
11496                                  * to the caller.
11497                                  */
11498                                 g_assert (cfg->ret);
11499                                 g_assert (mono_method_signature (method)->pinvoke); 
11500                                 CHECK_STACK (1);
11501                                 --sp;
11502                                 
11503                                 CHECK_OPSIZE (6);
11504                                 token = read32 (ip + 2);    
11505                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11506
11507                                 if (!cfg->vret_addr) {
11508                                         g_assert (cfg->ret_var_is_local);
11509
11510                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11511                                 } else {
11512                                         EMIT_NEW_RETLOADA (cfg, ins);
11513                                 }
11514                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11515                                 
11516                                 if (sp != stack_start)
11517                                         UNVERIFIED;
11518                                 
11519                                 MONO_INST_NEW (cfg, ins, OP_BR);
11520                                 ins->inst_target_bb = end_bblock;
11521                                 MONO_ADD_INS (bblock, ins);
11522                                 link_bblock (cfg, bblock, end_bblock);
11523                                 start_new_bblock = 1;
11524                                 ip += 6;
11525                                 break;
11526                         }
11527                         case CEE_MONO_CISINST:
11528                         case CEE_MONO_CCASTCLASS: {
11529                                 int token;
11530                                 CHECK_STACK (1);
11531                                 --sp;
11532                                 CHECK_OPSIZE (6);
11533                                 token = read32 (ip + 2);
11534                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11535                                 if (ip [1] == CEE_MONO_CISINST)
11536                                         ins = handle_cisinst (cfg, klass, sp [0]);
11537                                 else
11538                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11539                                 bblock = cfg->cbb;
11540                                 *sp++ = ins;
11541                                 ip += 6;
11542                                 break;
11543                         }
11544                         case CEE_MONO_SAVE_LMF:
11545                         case CEE_MONO_RESTORE_LMF:
11546 #ifdef MONO_ARCH_HAVE_LMF_OPS
11547                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11548                                 MONO_ADD_INS (bblock, ins);
11549                                 cfg->need_lmf_area = TRUE;
11550 #endif
11551                                 ip += 2;
11552                                 break;
11553                         case CEE_MONO_CLASSCONST:
11554                                 CHECK_STACK_OVF (1);
11555                                 CHECK_OPSIZE (6);
11556                                 token = read32 (ip + 2);
11557                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11558                                 *sp++ = ins;
11559                                 ip += 6;
11560                                 inline_costs += 10 * num_calls++;
11561                                 break;
11562                         case CEE_MONO_NOT_TAKEN:
11563                                 bblock->out_of_line = TRUE;
11564                                 ip += 2;
11565                                 break;
11566                         case CEE_MONO_TLS: {
11567                                 int key;
11568
11569                                 CHECK_STACK_OVF (1);
11570                                 CHECK_OPSIZE (6);
11571                                 key = (gint32)read32 (ip + 2);
11572                                 g_assert (key < TLS_KEY_NUM);
11573
11574                                 ins = mono_create_tls_get (cfg, key);
11575                                 if (!ins) {
11576                                         if (cfg->compile_aot) {
11577                                                 DISABLE_AOT (cfg);
11578                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11579                                                 ins->dreg = alloc_preg (cfg);
11580                                                 ins->type = STACK_PTR;
11581                                         } else {
11582                                                 g_assert_not_reached ();
11583                                         }
11584                                 }
11585                                 ins->type = STACK_PTR;
11586                                 MONO_ADD_INS (bblock, ins);
11587                                 *sp++ = ins;
11588                                 ip += 6;
11589                                 break;
11590                         }
11591                         case CEE_MONO_DYN_CALL: {
11592                                 MonoCallInst *call;
11593
11594                                 /* It would be easier to call a trampoline, but that would put an
11595                                  * extra frame on the stack, confusing exception handling. So
11596                                  * implement it inline using an opcode for now.
11597                                  */
11598
11599                                 if (!cfg->dyn_call_var) {
11600                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11601                                         /* prevent it from being register allocated */
11602                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11603                                 }
11604
11605                                 /* Has to use a call inst since it local regalloc expects it */
11606                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11607                                 ins = (MonoInst*)call;
11608                                 sp -= 2;
11609                                 ins->sreg1 = sp [0]->dreg;
11610                                 ins->sreg2 = sp [1]->dreg;
11611                                 MONO_ADD_INS (bblock, ins);
11612
11613                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11614
11615                                 ip += 2;
11616                                 inline_costs += 10 * num_calls++;
11617
11618                                 break;
11619                         }
11620                         case CEE_MONO_MEMORY_BARRIER: {
11621                                 CHECK_OPSIZE (5);
11622                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11623                                 ip += 5;
11624                                 break;
11625                         }
11626                         case CEE_MONO_JIT_ATTACH: {
11627                                 MonoInst *args [16], *domain_ins;
11628                                 MonoInst *ad_ins, *jit_tls_ins;
11629                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
11630
11631                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11632
11633                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11634                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11635
11636                                 ad_ins = mono_get_domain_intrinsic (cfg);
11637                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
11638
11639                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
11640                                         NEW_BBLOCK (cfg, next_bb);
11641                                         NEW_BBLOCK (cfg, call_bb);
11642
11643                                         if (cfg->compile_aot) {
11644                                                 /* AOT code is only used in the root domain */
11645                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
11646                                         } else {
11647                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
11648                                         }
11649                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11650                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
11651                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
11652
11653                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
11654                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
11655                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
11656
11657                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
11658                                         MONO_START_BB (cfg, call_bb);
11659                                 }
11660
11661                                 if (cfg->compile_aot) {
11662                                         /* AOT code is only used in the root domain */
11663                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11664                                 } else {
11665                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11666                                 }
11667                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11668                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11669
11670                                 if (next_bb) {
11671                                         MONO_START_BB (cfg, next_bb);
11672                                         bblock = cfg->cbb;
11673                                 }
11674                                 ip += 2;
11675                                 break;
11676                         }
11677                         case CEE_MONO_JIT_DETACH: {
11678                                 MonoInst *args [16];
11679
11680                                 /* Restore the original domain */
11681                                 dreg = alloc_ireg (cfg);
11682                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11683                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11684                                 ip += 2;
11685                                 break;
11686                         }
11687                         default:
11688                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11689                                 break;
11690                         }
11691                         break;
11692                 }
11693
11694                 case CEE_PREFIX1: {
11695                         CHECK_OPSIZE (2);
11696                         switch (ip [1]) {
11697                         case CEE_ARGLIST: {
11698                                 /* somewhat similar to LDTOKEN */
11699                                 MonoInst *addr, *vtvar;
11700                                 CHECK_STACK_OVF (1);
11701                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11702
11703                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11704                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11705
11706                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11707                                 ins->type = STACK_VTYPE;
11708                                 ins->klass = mono_defaults.argumenthandle_class;
11709                                 *sp++ = ins;
11710                                 ip += 2;
11711                                 break;
11712                         }
11713                         case CEE_CEQ:
11714                         case CEE_CGT:
11715                         case CEE_CGT_UN:
11716                         case CEE_CLT:
11717                         case CEE_CLT_UN: {
11718                                 MonoInst *cmp;
11719                                 CHECK_STACK (2);
11720                                 /*
11721                                  * The following transforms:
11722                                  *    CEE_CEQ    into OP_CEQ
11723                                  *    CEE_CGT    into OP_CGT
11724                                  *    CEE_CGT_UN into OP_CGT_UN
11725                                  *    CEE_CLT    into OP_CLT
11726                                  *    CEE_CLT_UN into OP_CLT_UN
11727                                  */
11728                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11729                                 
11730                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11731                                 sp -= 2;
11732                                 cmp->sreg1 = sp [0]->dreg;
11733                                 cmp->sreg2 = sp [1]->dreg;
11734                                 type_from_op (cmp, sp [0], sp [1]);
11735                                 CHECK_TYPE (cmp);
11736                                 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))))
11737                                         cmp->opcode = OP_LCOMPARE;
11738                                 else if (sp [0]->type == STACK_R8)
11739                                         cmp->opcode = OP_FCOMPARE;
11740                                 else
11741                                         cmp->opcode = OP_ICOMPARE;
11742                                 MONO_ADD_INS (bblock, cmp);
11743                                 ins->type = STACK_I4;
11744                                 ins->dreg = alloc_dreg (cfg, ins->type);
11745                                 type_from_op (ins, sp [0], sp [1]);
11746
11747                                 if (cmp->opcode == OP_FCOMPARE) {
11748                                         /*
11749                                          * The backends expect the fceq opcodes to do the
11750                                          * comparison too.
11751                                          */
11752                                         ins->sreg1 = cmp->sreg1;
11753                                         ins->sreg2 = cmp->sreg2;
11754                                         NULLIFY_INS (cmp);
11755                                 }
11756                                 MONO_ADD_INS (bblock, ins);
11757                                 *sp++ = ins;
11758                                 ip += 2;
11759                                 break;
11760                         }
11761                         case CEE_LDFTN: {
11762                                 MonoInst *argconst;
11763                                 MonoMethod *cil_method;
11764
11765                                 CHECK_STACK_OVF (1);
11766                                 CHECK_OPSIZE (6);
11767                                 n = read32 (ip + 2);
11768                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11769                                 if (!cmethod || mono_loader_get_last_error ())
11770                                         LOAD_ERROR;
11771                                 mono_class_init (cmethod->klass);
11772
11773                                 mono_save_token_info (cfg, image, n, cmethod);
11774
11775                                 context_used = mini_method_check_context_used (cfg, cmethod);
11776
11777                                 cil_method = cmethod;
11778                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11779                                         METHOD_ACCESS_FAILURE (method, cil_method);
11780
11781                                 if (mono_security_cas_enabled ()) {
11782                                         if (check_linkdemand (cfg, method, cmethod))
11783                                                 INLINE_FAILURE ("linkdemand");
11784                                         CHECK_CFG_EXCEPTION;
11785                                 } else if (mono_security_core_clr_enabled ()) {
11786                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11787                                 }
11788
11789                                 /* 
11790                                  * Optimize the common case of ldftn+delegate creation
11791                                  */
11792                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11793                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11794                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11795                                                 MonoInst *target_ins, *handle_ins;
11796                                                 MonoMethod *invoke;
11797                                                 int invoke_context_used;
11798
11799                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11800                                                 if (!invoke || !mono_method_signature (invoke))
11801                                                         LOAD_ERROR;
11802
11803                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11804
11805                                                 target_ins = sp [-1];
11806
11807                                                 if (mono_security_core_clr_enabled ())
11808                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11809
11810                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11811                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11812                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11813                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11814                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11815                                                         }
11816                                                 }
11817
11818 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11819                                                 /* FIXME: SGEN support */
11820                                                 if (invoke_context_used == 0) {
11821                                                         ip += 6;
11822                                                         if (cfg->verbose_level > 3)
11823                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11824                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
11825                                                                 sp --;
11826                                                                 *sp = handle_ins;
11827                                                                 CHECK_CFG_EXCEPTION;
11828                                                                 ip += 5;
11829                                                                 sp ++;
11830                                                                 break;
11831                                                         }
11832                                                         ip -= 6;
11833                                                 }
11834 #endif
11835                                         }
11836                                 }
11837
11838                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11839                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11840                                 *sp++ = ins;
11841                                 
11842                                 ip += 6;
11843                                 inline_costs += 10 * num_calls++;
11844                                 break;
11845                         }
11846                         case CEE_LDVIRTFTN: {
11847                                 MonoInst *args [2];
11848
11849                                 CHECK_STACK (1);
11850                                 CHECK_OPSIZE (6);
11851                                 n = read32 (ip + 2);
11852                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11853                                 if (!cmethod || mono_loader_get_last_error ())
11854                                         LOAD_ERROR;
11855                                 mono_class_init (cmethod->klass);
11856  
11857                                 context_used = mini_method_check_context_used (cfg, cmethod);
11858
11859                                 if (mono_security_cas_enabled ()) {
11860                                         if (check_linkdemand (cfg, method, cmethod))
11861                                                 INLINE_FAILURE ("linkdemand");
11862                                         CHECK_CFG_EXCEPTION;
11863                                 } else if (mono_security_core_clr_enabled ()) {
11864                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11865                                 }
11866
11867                                 /*
11868                                  * Optimize the common case of ldvirtftn+delegate creation
11869                                  */
11870                                 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)) {
11871                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11872                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11873                                                 MonoInst *target_ins, *handle_ins;
11874                                                 MonoMethod *invoke;
11875                                                 int invoke_context_used;
11876
11877                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11878                                                 if (!invoke || !mono_method_signature (invoke))
11879                                                         LOAD_ERROR;
11880
11881                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11882
11883                                                 target_ins = sp [-1];
11884
11885                                                 if (mono_security_core_clr_enabled ())
11886                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11887
11888 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11889                                                 /* FIXME: SGEN support */
11890                                                 if (invoke_context_used == 0) {
11891                                                         ip += 6;
11892                                                         if (cfg->verbose_level > 3)
11893                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11894                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, TRUE))) {
11895                                                                 sp -= 2;
11896                                                                 *sp = handle_ins;
11897                                                                 CHECK_CFG_EXCEPTION;
11898                                                                 ip += 5;
11899                                                                 sp ++;
11900                                                                 break;
11901                                                         }
11902                                                         ip -= 6;
11903                                                 }
11904 #endif
11905                                         }
11906                                 }
11907
11908                                 --sp;
11909                                 args [0] = *sp;
11910
11911                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11912                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11913
11914                                 if (context_used)
11915                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11916                                 else
11917                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11918
11919                                 ip += 6;
11920                                 inline_costs += 10 * num_calls++;
11921                                 break;
11922                         }
11923                         case CEE_LDARG:
11924                                 CHECK_STACK_OVF (1);
11925                                 CHECK_OPSIZE (4);
11926                                 n = read16 (ip + 2);
11927                                 CHECK_ARG (n);
11928                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11929                                 *sp++ = ins;
11930                                 ip += 4;
11931                                 break;
11932                         case CEE_LDARGA:
11933                                 CHECK_STACK_OVF (1);
11934                                 CHECK_OPSIZE (4);
11935                                 n = read16 (ip + 2);
11936                                 CHECK_ARG (n);
11937                                 NEW_ARGLOADA (cfg, ins, n);
11938                                 MONO_ADD_INS (cfg->cbb, ins);
11939                                 *sp++ = ins;
11940                                 ip += 4;
11941                                 break;
11942                         case CEE_STARG:
11943                                 CHECK_STACK (1);
11944                                 --sp;
11945                                 CHECK_OPSIZE (4);
11946                                 n = read16 (ip + 2);
11947                                 CHECK_ARG (n);
11948                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11949                                         UNVERIFIED;
11950                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11951                                 ip += 4;
11952                                 break;
11953                         case CEE_LDLOC:
11954                                 CHECK_STACK_OVF (1);
11955                                 CHECK_OPSIZE (4);
11956                                 n = read16 (ip + 2);
11957                                 CHECK_LOCAL (n);
11958                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11959                                 *sp++ = ins;
11960                                 ip += 4;
11961                                 break;
11962                         case CEE_LDLOCA: {
11963                                 unsigned char *tmp_ip;
11964                                 CHECK_STACK_OVF (1);
11965                                 CHECK_OPSIZE (4);
11966                                 n = read16 (ip + 2);
11967                                 CHECK_LOCAL (n);
11968
11969                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11970                                         ip = tmp_ip;
11971                                         inline_costs += 1;
11972                                         break;
11973                                 }                       
11974                                 
11975                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11976                                 *sp++ = ins;
11977                                 ip += 4;
11978                                 break;
11979                         }
11980                         case CEE_STLOC:
11981                                 CHECK_STACK (1);
11982                                 --sp;
11983                                 CHECK_OPSIZE (4);
11984                                 n = read16 (ip + 2);
11985                                 CHECK_LOCAL (n);
11986                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11987                                         UNVERIFIED;
11988                                 emit_stloc_ir (cfg, sp, header, n);
11989                                 ip += 4;
11990                                 inline_costs += 1;
11991                                 break;
11992                         case CEE_LOCALLOC:
11993                                 CHECK_STACK (1);
11994                                 --sp;
11995                                 if (sp != stack_start) 
11996                                         UNVERIFIED;
11997                                 if (cfg->method != method) 
11998                                         /* 
11999                                          * Inlining this into a loop in a parent could lead to 
12000                                          * stack overflows which is different behavior than the
12001                                          * non-inlined case, thus disable inlining in this case.
12002                                          */
12003                                         INLINE_FAILURE("localloc");
12004
12005                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12006                                 ins->dreg = alloc_preg (cfg);
12007                                 ins->sreg1 = sp [0]->dreg;
12008                                 ins->type = STACK_PTR;
12009                                 MONO_ADD_INS (cfg->cbb, ins);
12010
12011                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12012                                 if (init_locals)
12013                                         ins->flags |= MONO_INST_INIT;
12014
12015                                 *sp++ = ins;
12016                                 ip += 2;
12017                                 break;
12018                         case CEE_ENDFILTER: {
12019                                 MonoExceptionClause *clause, *nearest;
12020                                 int cc, nearest_num;
12021
12022                                 CHECK_STACK (1);
12023                                 --sp;
12024                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12025                                         UNVERIFIED;
12026                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12027                                 ins->sreg1 = (*sp)->dreg;
12028                                 MONO_ADD_INS (bblock, ins);
12029                                 start_new_bblock = 1;
12030                                 ip += 2;
12031
12032                                 nearest = NULL;
12033                                 nearest_num = 0;
12034                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12035                                         clause = &header->clauses [cc];
12036                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12037                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12038                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
12039                                                 nearest = clause;
12040                                                 nearest_num = cc;
12041                                         }
12042                                 }
12043                                 g_assert (nearest);
12044                                 if ((ip - header->code) != nearest->handler_offset)
12045                                         UNVERIFIED;
12046
12047                                 break;
12048                         }
12049                         case CEE_UNALIGNED_:
12050                                 ins_flag |= MONO_INST_UNALIGNED;
12051                                 /* FIXME: record alignment? we can assume 1 for now */
12052                                 CHECK_OPSIZE (3);
12053                                 ip += 3;
12054                                 break;
12055                         case CEE_VOLATILE_:
12056                                 ins_flag |= MONO_INST_VOLATILE;
12057                                 ip += 2;
12058                                 break;
12059                         case CEE_TAIL_:
12060                                 ins_flag   |= MONO_INST_TAILCALL;
12061                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12062                                 /* Can't inline tail calls at this time */
12063                                 inline_costs += 100000;
12064                                 ip += 2;
12065                                 break;
12066                         case CEE_INITOBJ:
12067                                 CHECK_STACK (1);
12068                                 --sp;
12069                                 CHECK_OPSIZE (6);
12070                                 token = read32 (ip + 2);
12071                                 klass = mini_get_class (method, token, generic_context);
12072                                 CHECK_TYPELOAD (klass);
12073                                 if (generic_class_is_reference_type (cfg, klass))
12074                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12075                                 else
12076                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12077                                 ip += 6;
12078                                 inline_costs += 1;
12079                                 break;
12080                         case CEE_CONSTRAINED_:
12081                                 CHECK_OPSIZE (6);
12082                                 token = read32 (ip + 2);
12083                                 constrained_call = mini_get_class (method, token, generic_context);
12084                                 CHECK_TYPELOAD (constrained_call);
12085                                 ip += 6;
12086                                 break;
12087                         case CEE_CPBLK:
12088                         case CEE_INITBLK: {
12089                                 MonoInst *iargs [3];
12090                                 CHECK_STACK (3);
12091                                 sp -= 3;
12092
12093                                 /* Skip optimized paths for volatile operations. */
12094                                 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)) {
12095                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12096                                 } 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)) {
12097                                         /* emit_memset only works when val == 0 */
12098                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12099                                 } else {
12100                                         MonoInst *call;
12101                                         iargs [0] = sp [0];
12102                                         iargs [1] = sp [1];
12103                                         iargs [2] = sp [2];
12104                                         if (ip [1] == CEE_CPBLK) {
12105                                                 /*
12106                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12107                                                  * and release barriers for cpblk. It is technically both a load and
12108                                                  * store operation, so it seems like that's the sensible thing to do.
12109                                                  */
12110                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12111                                                 if (ins_flag & MONO_INST_VOLATILE) {
12112                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12113                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
12114                                                         emit_memory_barrier (cfg, FullBarrier);
12115                                                 }
12116                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12117                                                 call->flags |= ins_flag;
12118                                                 if (ins_flag & MONO_INST_VOLATILE) {
12119                                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
12120                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
12121                                                         emit_memory_barrier (cfg, FullBarrier);
12122                                                 }
12123                                         } else {
12124                                                 MonoMethod *memset_method = get_memset_method ();
12125                                                 if (ins_flag & MONO_INST_VOLATILE) {
12126                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12127                                                         /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
12128                                                         emit_memory_barrier (cfg, FullBarrier);
12129                                                 }
12130                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12131                                                 call->flags |= ins_flag;
12132                                         }
12133                                 }
12134                                 ip += 2;
12135                                 ins_flag = 0;
12136                                 inline_costs += 1;
12137                                 break;
12138                         }
12139                         case CEE_NO_:
12140                                 CHECK_OPSIZE (3);
12141                                 if (ip [2] & 0x1)
12142                                         ins_flag |= MONO_INST_NOTYPECHECK;
12143                                 if (ip [2] & 0x2)
12144                                         ins_flag |= MONO_INST_NORANGECHECK;
12145                                 /* we ignore the no-nullcheck for now since we
12146                                  * really do it explicitly only when doing callvirt->call
12147                                  */
12148                                 ip += 3;
12149                                 break;
12150                         case CEE_RETHROW: {
12151                                 MonoInst *load;
12152                                 int handler_offset = -1;
12153
12154                                 for (i = 0; i < header->num_clauses; ++i) {
12155                                         MonoExceptionClause *clause = &header->clauses [i];
12156                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12157                                                 handler_offset = clause->handler_offset;
12158                                                 break;
12159                                         }
12160                                 }
12161
12162                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12163
12164                                 if (handler_offset == -1)
12165                                         UNVERIFIED;
12166
12167                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12168                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12169                                 ins->sreg1 = load->dreg;
12170                                 MONO_ADD_INS (bblock, ins);
12171
12172                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12173                                 MONO_ADD_INS (bblock, ins);
12174
12175                                 sp = stack_start;
12176                                 link_bblock (cfg, bblock, end_bblock);
12177                                 start_new_bblock = 1;
12178                                 ip += 2;
12179                                 break;
12180                         }
12181                         case CEE_SIZEOF: {
12182                                 guint32 val;
12183                                 int ialign;
12184
12185                                 CHECK_STACK_OVF (1);
12186                                 CHECK_OPSIZE (6);
12187                                 token = read32 (ip + 2);
12188                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12189                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12190                                         CHECK_CFG_ERROR;
12191
12192                                         val = mono_type_size (type, &ialign);
12193                                 } else {
12194                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12195                                         CHECK_TYPELOAD (klass);
12196
12197                                         val = mono_type_size (&klass->byval_arg, &ialign);
12198
12199                                         if (mini_is_gsharedvt_klass (cfg, klass))
12200                                                 GSHAREDVT_FAILURE (*ip);
12201                                 }
12202                                 EMIT_NEW_ICONST (cfg, ins, val);
12203                                 *sp++= ins;
12204                                 ip += 6;
12205                                 break;
12206                         }
12207                         case CEE_REFANYTYPE: {
12208                                 MonoInst *src_var, *src;
12209
12210                                 GSHAREDVT_FAILURE (*ip);
12211
12212                                 CHECK_STACK (1);
12213                                 --sp;
12214
12215                                 // FIXME:
12216                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12217                                 if (!src_var)
12218                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12219                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12220                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12221                                 *sp++ = ins;
12222                                 ip += 2;
12223                                 break;
12224                         }
12225                         case CEE_READONLY_:
12226                                 readonly = TRUE;
12227                                 ip += 2;
12228                                 break;
12229
12230                         case CEE_UNUSED56:
12231                         case CEE_UNUSED57:
12232                         case CEE_UNUSED70:
12233                         case CEE_UNUSED:
12234                         case CEE_UNUSED99:
12235                                 UNVERIFIED;
12236                                 
12237                         default:
12238                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12239                                 UNVERIFIED;
12240                         }
12241                         break;
12242                 }
12243                 case CEE_UNUSED58:
12244                 case CEE_UNUSED1:
12245                         UNVERIFIED;
12246
12247                 default:
12248                         g_warning ("opcode 0x%02x not handled", *ip);
12249                         UNVERIFIED;
12250                 }
12251         }
12252         if (start_new_bblock != 1)
12253                 UNVERIFIED;
12254
12255         bblock->cil_length = ip - bblock->cil_code;
12256         if (bblock->next_bb) {
12257                 /* This could already be set because of inlining, #693905 */
12258                 MonoBasicBlock *bb = bblock;
12259
12260                 while (bb->next_bb)
12261                         bb = bb->next_bb;
12262                 bb->next_bb = end_bblock;
12263         } else {
12264                 bblock->next_bb = end_bblock;
12265         }
12266
12267         if (cfg->method == method && cfg->domainvar) {
12268                 MonoInst *store;
12269                 MonoInst *get_domain;
12270
12271                 cfg->cbb = init_localsbb;
12272
12273                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12274                         MONO_ADD_INS (cfg->cbb, get_domain);
12275                 } else {
12276                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12277                 }
12278                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12279                 MONO_ADD_INS (cfg->cbb, store);
12280         }
12281
12282 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12283         if (cfg->compile_aot)
12284                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12285                 mono_get_got_var (cfg);
12286 #endif
12287
12288         if (cfg->method == method && cfg->got_var)
12289                 mono_emit_load_got_addr (cfg);
12290
12291         if (init_localsbb) {
12292                 cfg->cbb = init_localsbb;
12293                 cfg->ip = NULL;
12294                 for (i = 0; i < header->num_locals; ++i) {
12295                         emit_init_local (cfg, i, header->locals [i], init_locals);
12296                 }
12297         }
12298
12299         if (cfg->init_ref_vars && cfg->method == method) {
12300                 /* Emit initialization for ref vars */
12301                 // FIXME: Avoid duplication initialization for IL locals.
12302                 for (i = 0; i < cfg->num_varinfo; ++i) {
12303                         MonoInst *ins = cfg->varinfo [i];
12304
12305                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12306                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12307                 }
12308         }
12309
12310         if (cfg->lmf_var && cfg->method == method) {
12311                 cfg->cbb = init_localsbb;
12312                 emit_push_lmf (cfg);
12313         }
12314
12315         cfg->cbb = init_localsbb;
12316         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12317
12318         if (seq_points) {
12319                 MonoBasicBlock *bb;
12320
12321                 /*
12322                  * Make seq points at backward branch targets interruptable.
12323                  */
12324                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12325                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12326                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12327         }
12328
12329         /* Add a sequence point for method entry/exit events */
12330         if (cfg->gen_seq_points_debug_data) {
12331                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12332                 MONO_ADD_INS (init_localsbb, ins);
12333                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12334                 MONO_ADD_INS (cfg->bb_exit, ins);
12335         }
12336
12337         /*
12338          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12339          * the code they refer to was dead (#11880).
12340          */
12341         if (sym_seq_points) {
12342                 for (i = 0; i < header->code_size; ++i) {
12343                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12344                                 MonoInst *ins;
12345
12346                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12347                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12348                         }
12349                 }
12350         }
12351
12352         cfg->ip = NULL;
12353
12354         if (cfg->method == method) {
12355                 MonoBasicBlock *bb;
12356                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12357                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12358                         if (cfg->spvars)
12359                                 mono_create_spvar_for_region (cfg, bb->region);
12360                         if (cfg->verbose_level > 2)
12361                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12362                 }
12363         }
12364
12365         if (inline_costs < 0) {
12366                 char *mname;
12367
12368                 /* Method is too large */
12369                 mname = mono_method_full_name (method, TRUE);
12370                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12371                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12372                 g_free (mname);
12373         }
12374
12375         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12376                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12377
12378         goto cleanup;
12379
12380 mono_error_exit:
12381         g_assert (!mono_error_ok (&cfg->error));
12382         goto cleanup;
12383  
12384  exception_exit:
12385         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12386         goto cleanup;
12387
12388  unverified:
12389         set_exception_type_from_invalid_il (cfg, method, ip);
12390         goto cleanup;
12391
12392  cleanup:
12393         g_slist_free (class_inits);
12394         mono_basic_block_free (original_bb);
12395         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
12396         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12397         if (cfg->exception_type)
12398                 return -1;
12399         else
12400                 return inline_costs;
12401 }
12402
12403 static int
12404 store_membase_reg_to_store_membase_imm (int opcode)
12405 {
12406         switch (opcode) {
12407         case OP_STORE_MEMBASE_REG:
12408                 return OP_STORE_MEMBASE_IMM;
12409         case OP_STOREI1_MEMBASE_REG:
12410                 return OP_STOREI1_MEMBASE_IMM;
12411         case OP_STOREI2_MEMBASE_REG:
12412                 return OP_STOREI2_MEMBASE_IMM;
12413         case OP_STOREI4_MEMBASE_REG:
12414                 return OP_STOREI4_MEMBASE_IMM;
12415         case OP_STOREI8_MEMBASE_REG:
12416                 return OP_STOREI8_MEMBASE_IMM;
12417         default:
12418                 g_assert_not_reached ();
12419         }
12420
12421         return -1;
12422 }               
12423
12424 int
12425 mono_op_to_op_imm (int opcode)
12426 {
12427         switch (opcode) {
12428         case OP_IADD:
12429                 return OP_IADD_IMM;
12430         case OP_ISUB:
12431                 return OP_ISUB_IMM;
12432         case OP_IDIV:
12433                 return OP_IDIV_IMM;
12434         case OP_IDIV_UN:
12435                 return OP_IDIV_UN_IMM;
12436         case OP_IREM:
12437                 return OP_IREM_IMM;
12438         case OP_IREM_UN:
12439                 return OP_IREM_UN_IMM;
12440         case OP_IMUL:
12441                 return OP_IMUL_IMM;
12442         case OP_IAND:
12443                 return OP_IAND_IMM;
12444         case OP_IOR:
12445                 return OP_IOR_IMM;
12446         case OP_IXOR:
12447                 return OP_IXOR_IMM;
12448         case OP_ISHL:
12449                 return OP_ISHL_IMM;
12450         case OP_ISHR:
12451                 return OP_ISHR_IMM;
12452         case OP_ISHR_UN:
12453                 return OP_ISHR_UN_IMM;
12454
12455         case OP_LADD:
12456                 return OP_LADD_IMM;
12457         case OP_LSUB:
12458                 return OP_LSUB_IMM;
12459         case OP_LAND:
12460                 return OP_LAND_IMM;
12461         case OP_LOR:
12462                 return OP_LOR_IMM;
12463         case OP_LXOR:
12464                 return OP_LXOR_IMM;
12465         case OP_LSHL:
12466                 return OP_LSHL_IMM;
12467         case OP_LSHR:
12468                 return OP_LSHR_IMM;
12469         case OP_LSHR_UN:
12470                 return OP_LSHR_UN_IMM;
12471 #if SIZEOF_REGISTER == 8
12472         case OP_LREM:
12473                 return OP_LREM_IMM;
12474 #endif
12475
12476         case OP_COMPARE:
12477                 return OP_COMPARE_IMM;
12478         case OP_ICOMPARE:
12479                 return OP_ICOMPARE_IMM;
12480         case OP_LCOMPARE:
12481                 return OP_LCOMPARE_IMM;
12482
12483         case OP_STORE_MEMBASE_REG:
12484                 return OP_STORE_MEMBASE_IMM;
12485         case OP_STOREI1_MEMBASE_REG:
12486                 return OP_STOREI1_MEMBASE_IMM;
12487         case OP_STOREI2_MEMBASE_REG:
12488                 return OP_STOREI2_MEMBASE_IMM;
12489         case OP_STOREI4_MEMBASE_REG:
12490                 return OP_STOREI4_MEMBASE_IMM;
12491
12492 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12493         case OP_X86_PUSH:
12494                 return OP_X86_PUSH_IMM;
12495         case OP_X86_COMPARE_MEMBASE_REG:
12496                 return OP_X86_COMPARE_MEMBASE_IMM;
12497 #endif
12498 #if defined(TARGET_AMD64)
12499         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12500                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12501 #endif
12502         case OP_VOIDCALL_REG:
12503                 return OP_VOIDCALL;
12504         case OP_CALL_REG:
12505                 return OP_CALL;
12506         case OP_LCALL_REG:
12507                 return OP_LCALL;
12508         case OP_FCALL_REG:
12509                 return OP_FCALL;
12510         case OP_LOCALLOC:
12511                 return OP_LOCALLOC_IMM;
12512         }
12513
12514         return -1;
12515 }
12516
12517 static int
12518 ldind_to_load_membase (int opcode)
12519 {
12520         switch (opcode) {
12521         case CEE_LDIND_I1:
12522                 return OP_LOADI1_MEMBASE;
12523         case CEE_LDIND_U1:
12524                 return OP_LOADU1_MEMBASE;
12525         case CEE_LDIND_I2:
12526                 return OP_LOADI2_MEMBASE;
12527         case CEE_LDIND_U2:
12528                 return OP_LOADU2_MEMBASE;
12529         case CEE_LDIND_I4:
12530                 return OP_LOADI4_MEMBASE;
12531         case CEE_LDIND_U4:
12532                 return OP_LOADU4_MEMBASE;
12533         case CEE_LDIND_I:
12534                 return OP_LOAD_MEMBASE;
12535         case CEE_LDIND_REF:
12536                 return OP_LOAD_MEMBASE;
12537         case CEE_LDIND_I8:
12538                 return OP_LOADI8_MEMBASE;
12539         case CEE_LDIND_R4:
12540                 return OP_LOADR4_MEMBASE;
12541         case CEE_LDIND_R8:
12542                 return OP_LOADR8_MEMBASE;
12543         default:
12544                 g_assert_not_reached ();
12545         }
12546
12547         return -1;
12548 }
12549
12550 static int
12551 stind_to_store_membase (int opcode)
12552 {
12553         switch (opcode) {
12554         case CEE_STIND_I1:
12555                 return OP_STOREI1_MEMBASE_REG;
12556         case CEE_STIND_I2:
12557                 return OP_STOREI2_MEMBASE_REG;
12558         case CEE_STIND_I4:
12559                 return OP_STOREI4_MEMBASE_REG;
12560         case CEE_STIND_I:
12561         case CEE_STIND_REF:
12562                 return OP_STORE_MEMBASE_REG;
12563         case CEE_STIND_I8:
12564                 return OP_STOREI8_MEMBASE_REG;
12565         case CEE_STIND_R4:
12566                 return OP_STORER4_MEMBASE_REG;
12567         case CEE_STIND_R8:
12568                 return OP_STORER8_MEMBASE_REG;
12569         default:
12570                 g_assert_not_reached ();
12571         }
12572
12573         return -1;
12574 }
12575
12576 int
12577 mono_load_membase_to_load_mem (int opcode)
12578 {
12579         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12580 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12581         switch (opcode) {
12582         case OP_LOAD_MEMBASE:
12583                 return OP_LOAD_MEM;
12584         case OP_LOADU1_MEMBASE:
12585                 return OP_LOADU1_MEM;
12586         case OP_LOADU2_MEMBASE:
12587                 return OP_LOADU2_MEM;
12588         case OP_LOADI4_MEMBASE:
12589                 return OP_LOADI4_MEM;
12590         case OP_LOADU4_MEMBASE:
12591                 return OP_LOADU4_MEM;
12592 #if SIZEOF_REGISTER == 8
12593         case OP_LOADI8_MEMBASE:
12594                 return OP_LOADI8_MEM;
12595 #endif
12596         }
12597 #endif
12598
12599         return -1;
12600 }
12601
12602 static inline int
12603 op_to_op_dest_membase (int store_opcode, int opcode)
12604 {
12605 #if defined(TARGET_X86)
12606         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12607                 return -1;
12608
12609         switch (opcode) {
12610         case OP_IADD:
12611                 return OP_X86_ADD_MEMBASE_REG;
12612         case OP_ISUB:
12613                 return OP_X86_SUB_MEMBASE_REG;
12614         case OP_IAND:
12615                 return OP_X86_AND_MEMBASE_REG;
12616         case OP_IOR:
12617                 return OP_X86_OR_MEMBASE_REG;
12618         case OP_IXOR:
12619                 return OP_X86_XOR_MEMBASE_REG;
12620         case OP_ADD_IMM:
12621         case OP_IADD_IMM:
12622                 return OP_X86_ADD_MEMBASE_IMM;
12623         case OP_SUB_IMM:
12624         case OP_ISUB_IMM:
12625                 return OP_X86_SUB_MEMBASE_IMM;
12626         case OP_AND_IMM:
12627         case OP_IAND_IMM:
12628                 return OP_X86_AND_MEMBASE_IMM;
12629         case OP_OR_IMM:
12630         case OP_IOR_IMM:
12631                 return OP_X86_OR_MEMBASE_IMM;
12632         case OP_XOR_IMM:
12633         case OP_IXOR_IMM:
12634                 return OP_X86_XOR_MEMBASE_IMM;
12635         case OP_MOVE:
12636                 return OP_NOP;
12637         }
12638 #endif
12639
12640 #if defined(TARGET_AMD64)
12641         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12642                 return -1;
12643
12644         switch (opcode) {
12645         case OP_IADD:
12646                 return OP_X86_ADD_MEMBASE_REG;
12647         case OP_ISUB:
12648                 return OP_X86_SUB_MEMBASE_REG;
12649         case OP_IAND:
12650                 return OP_X86_AND_MEMBASE_REG;
12651         case OP_IOR:
12652                 return OP_X86_OR_MEMBASE_REG;
12653         case OP_IXOR:
12654                 return OP_X86_XOR_MEMBASE_REG;
12655         case OP_IADD_IMM:
12656                 return OP_X86_ADD_MEMBASE_IMM;
12657         case OP_ISUB_IMM:
12658                 return OP_X86_SUB_MEMBASE_IMM;
12659         case OP_IAND_IMM:
12660                 return OP_X86_AND_MEMBASE_IMM;
12661         case OP_IOR_IMM:
12662                 return OP_X86_OR_MEMBASE_IMM;
12663         case OP_IXOR_IMM:
12664                 return OP_X86_XOR_MEMBASE_IMM;
12665         case OP_LADD:
12666                 return OP_AMD64_ADD_MEMBASE_REG;
12667         case OP_LSUB:
12668                 return OP_AMD64_SUB_MEMBASE_REG;
12669         case OP_LAND:
12670                 return OP_AMD64_AND_MEMBASE_REG;
12671         case OP_LOR:
12672                 return OP_AMD64_OR_MEMBASE_REG;
12673         case OP_LXOR:
12674                 return OP_AMD64_XOR_MEMBASE_REG;
12675         case OP_ADD_IMM:
12676         case OP_LADD_IMM:
12677                 return OP_AMD64_ADD_MEMBASE_IMM;
12678         case OP_SUB_IMM:
12679         case OP_LSUB_IMM:
12680                 return OP_AMD64_SUB_MEMBASE_IMM;
12681         case OP_AND_IMM:
12682         case OP_LAND_IMM:
12683                 return OP_AMD64_AND_MEMBASE_IMM;
12684         case OP_OR_IMM:
12685         case OP_LOR_IMM:
12686                 return OP_AMD64_OR_MEMBASE_IMM;
12687         case OP_XOR_IMM:
12688         case OP_LXOR_IMM:
12689                 return OP_AMD64_XOR_MEMBASE_IMM;
12690         case OP_MOVE:
12691                 return OP_NOP;
12692         }
12693 #endif
12694
12695         return -1;
12696 }
12697
12698 static inline int
12699 op_to_op_store_membase (int store_opcode, int opcode)
12700 {
12701 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12702         switch (opcode) {
12703         case OP_ICEQ:
12704                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12705                         return OP_X86_SETEQ_MEMBASE;
12706         case OP_CNE:
12707                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12708                         return OP_X86_SETNE_MEMBASE;
12709         }
12710 #endif
12711
12712         return -1;
12713 }
12714
12715 static inline int
12716 op_to_op_src1_membase (int load_opcode, int opcode)
12717 {
12718 #ifdef TARGET_X86
12719         /* FIXME: This has sign extension issues */
12720         /*
12721         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12722                 return OP_X86_COMPARE_MEMBASE8_IMM;
12723         */
12724
12725         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12726                 return -1;
12727
12728         switch (opcode) {
12729         case OP_X86_PUSH:
12730                 return OP_X86_PUSH_MEMBASE;
12731         case OP_COMPARE_IMM:
12732         case OP_ICOMPARE_IMM:
12733                 return OP_X86_COMPARE_MEMBASE_IMM;
12734         case OP_COMPARE:
12735         case OP_ICOMPARE:
12736                 return OP_X86_COMPARE_MEMBASE_REG;
12737         }
12738 #endif
12739
12740 #ifdef TARGET_AMD64
12741         /* FIXME: This has sign extension issues */
12742         /*
12743         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12744                 return OP_X86_COMPARE_MEMBASE8_IMM;
12745         */
12746
12747         switch (opcode) {
12748         case OP_X86_PUSH:
12749 #ifdef __mono_ilp32__
12750                 if (load_opcode == OP_LOADI8_MEMBASE)
12751 #else
12752                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12753 #endif
12754                         return OP_X86_PUSH_MEMBASE;
12755                 break;
12756                 /* FIXME: This only works for 32 bit immediates
12757         case OP_COMPARE_IMM:
12758         case OP_LCOMPARE_IMM:
12759                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12760                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12761                 */
12762         case OP_ICOMPARE_IMM:
12763                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12764                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12765                 break;
12766         case OP_COMPARE:
12767         case OP_LCOMPARE:
12768 #ifdef __mono_ilp32__
12769                 if (load_opcode == OP_LOAD_MEMBASE)
12770                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12771                 if (load_opcode == OP_LOADI8_MEMBASE)
12772 #else
12773                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12774 #endif
12775                         return OP_AMD64_COMPARE_MEMBASE_REG;
12776                 break;
12777         case OP_ICOMPARE:
12778                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12779                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12780                 break;
12781         }
12782 #endif
12783
12784         return -1;
12785 }
12786
12787 static inline int
12788 op_to_op_src2_membase (int load_opcode, int opcode)
12789 {
12790 #ifdef TARGET_X86
12791         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12792                 return -1;
12793         
12794         switch (opcode) {
12795         case OP_COMPARE:
12796         case OP_ICOMPARE:
12797                 return OP_X86_COMPARE_REG_MEMBASE;
12798         case OP_IADD:
12799                 return OP_X86_ADD_REG_MEMBASE;
12800         case OP_ISUB:
12801                 return OP_X86_SUB_REG_MEMBASE;
12802         case OP_IAND:
12803                 return OP_X86_AND_REG_MEMBASE;
12804         case OP_IOR:
12805                 return OP_X86_OR_REG_MEMBASE;
12806         case OP_IXOR:
12807                 return OP_X86_XOR_REG_MEMBASE;
12808         }
12809 #endif
12810
12811 #ifdef TARGET_AMD64
12812 #ifdef __mono_ilp32__
12813         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12814 #else
12815         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12816 #endif
12817                 switch (opcode) {
12818                 case OP_ICOMPARE:
12819                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12820                 case OP_IADD:
12821                         return OP_X86_ADD_REG_MEMBASE;
12822                 case OP_ISUB:
12823                         return OP_X86_SUB_REG_MEMBASE;
12824                 case OP_IAND:
12825                         return OP_X86_AND_REG_MEMBASE;
12826                 case OP_IOR:
12827                         return OP_X86_OR_REG_MEMBASE;
12828                 case OP_IXOR:
12829                         return OP_X86_XOR_REG_MEMBASE;
12830                 }
12831 #ifdef __mono_ilp32__
12832         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12833 #else
12834         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12835 #endif
12836                 switch (opcode) {
12837                 case OP_COMPARE:
12838                 case OP_LCOMPARE:
12839                         return OP_AMD64_COMPARE_REG_MEMBASE;
12840                 case OP_LADD:
12841                         return OP_AMD64_ADD_REG_MEMBASE;
12842                 case OP_LSUB:
12843                         return OP_AMD64_SUB_REG_MEMBASE;
12844                 case OP_LAND:
12845                         return OP_AMD64_AND_REG_MEMBASE;
12846                 case OP_LOR:
12847                         return OP_AMD64_OR_REG_MEMBASE;
12848                 case OP_LXOR:
12849                         return OP_AMD64_XOR_REG_MEMBASE;
12850                 }
12851         }
12852 #endif
12853
12854         return -1;
12855 }
12856
12857 int
12858 mono_op_to_op_imm_noemul (int opcode)
12859 {
12860         switch (opcode) {
12861 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12862         case OP_LSHR:
12863         case OP_LSHL:
12864         case OP_LSHR_UN:
12865                 return -1;
12866 #endif
12867 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12868         case OP_IDIV:
12869         case OP_IDIV_UN:
12870         case OP_IREM:
12871         case OP_IREM_UN:
12872                 return -1;
12873 #endif
12874 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12875         case OP_IMUL:
12876                 return -1;
12877 #endif
12878         default:
12879                 return mono_op_to_op_imm (opcode);
12880         }
12881 }
12882
12883 /**
12884  * mono_handle_global_vregs:
12885  *
12886  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12887  * for them.
12888  */
12889 void
12890 mono_handle_global_vregs (MonoCompile *cfg)
12891 {
12892         gint32 *vreg_to_bb;
12893         MonoBasicBlock *bb;
12894         int i, pos;
12895
12896         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12897
12898 #ifdef MONO_ARCH_SIMD_INTRINSICS
12899         if (cfg->uses_simd_intrinsics)
12900                 mono_simd_simplify_indirection (cfg);
12901 #endif
12902
12903         /* Find local vregs used in more than one bb */
12904         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12905                 MonoInst *ins = bb->code;       
12906                 int block_num = bb->block_num;
12907
12908                 if (cfg->verbose_level > 2)
12909                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12910
12911                 cfg->cbb = bb;
12912                 for (; ins; ins = ins->next) {
12913                         const char *spec = INS_INFO (ins->opcode);
12914                         int regtype = 0, regindex;
12915                         gint32 prev_bb;
12916
12917                         if (G_UNLIKELY (cfg->verbose_level > 2))
12918                                 mono_print_ins (ins);
12919
12920                         g_assert (ins->opcode >= MONO_CEE_LAST);
12921
12922                         for (regindex = 0; regindex < 4; regindex ++) {
12923                                 int vreg = 0;
12924
12925                                 if (regindex == 0) {
12926                                         regtype = spec [MONO_INST_DEST];
12927                                         if (regtype == ' ')
12928                                                 continue;
12929                                         vreg = ins->dreg;
12930                                 } else if (regindex == 1) {
12931                                         regtype = spec [MONO_INST_SRC1];
12932                                         if (regtype == ' ')
12933                                                 continue;
12934                                         vreg = ins->sreg1;
12935                                 } else if (regindex == 2) {
12936                                         regtype = spec [MONO_INST_SRC2];
12937                                         if (regtype == ' ')
12938                                                 continue;
12939                                         vreg = ins->sreg2;
12940                                 } else if (regindex == 3) {
12941                                         regtype = spec [MONO_INST_SRC3];
12942                                         if (regtype == ' ')
12943                                                 continue;
12944                                         vreg = ins->sreg3;
12945                                 }
12946
12947 #if SIZEOF_REGISTER == 4
12948                                 /* In the LLVM case, the long opcodes are not decomposed */
12949                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12950                                         /*
12951                                          * Since some instructions reference the original long vreg,
12952                                          * and some reference the two component vregs, it is quite hard
12953                                          * to determine when it needs to be global. So be conservative.
12954                                          */
12955                                         if (!get_vreg_to_inst (cfg, vreg)) {
12956                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12957
12958                                                 if (cfg->verbose_level > 2)
12959                                                         printf ("LONG VREG R%d made global.\n", vreg);
12960                                         }
12961
12962                                         /*
12963                                          * Make the component vregs volatile since the optimizations can
12964                                          * get confused otherwise.
12965                                          */
12966                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12967                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12968                                 }
12969 #endif
12970
12971                                 g_assert (vreg != -1);
12972
12973                                 prev_bb = vreg_to_bb [vreg];
12974                                 if (prev_bb == 0) {
12975                                         /* 0 is a valid block num */
12976                                         vreg_to_bb [vreg] = block_num + 1;
12977                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12978                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12979                                                 continue;
12980
12981                                         if (!get_vreg_to_inst (cfg, vreg)) {
12982                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12983                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12984
12985                                                 switch (regtype) {
12986                                                 case 'i':
12987                                                         if (vreg_is_ref (cfg, vreg))
12988                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12989                                                         else
12990                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12991                                                         break;
12992                                                 case 'l':
12993                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12994                                                         break;
12995                                                 case 'f':
12996                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12997                                                         break;
12998                                                 case 'v':
12999                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13000                                                         break;
13001                                                 default:
13002                                                         g_assert_not_reached ();
13003                                                 }
13004                                         }
13005
13006                                         /* Flag as having been used in more than one bb */
13007                                         vreg_to_bb [vreg] = -1;
13008                                 }
13009                         }
13010                 }
13011         }
13012
13013         /* If a variable is used in only one bblock, convert it into a local vreg */
13014         for (i = 0; i < cfg->num_varinfo; i++) {
13015                 MonoInst *var = cfg->varinfo [i];
13016                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13017
13018                 switch (var->type) {
13019                 case STACK_I4:
13020                 case STACK_OBJ:
13021                 case STACK_PTR:
13022                 case STACK_MP:
13023                 case STACK_VTYPE:
13024 #if SIZEOF_REGISTER == 8
13025                 case STACK_I8:
13026 #endif
13027 #if !defined(TARGET_X86)
13028                 /* Enabling this screws up the fp stack on x86 */
13029                 case STACK_R8:
13030 #endif
13031                         if (mono_arch_is_soft_float ())
13032                                 break;
13033
13034                         /* Arguments are implicitly global */
13035                         /* Putting R4 vars into registers doesn't work currently */
13036                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13037                         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) {
13038                                 /* 
13039                                  * Make that the variable's liveness interval doesn't contain a call, since
13040                                  * that would cause the lvreg to be spilled, making the whole optimization
13041                                  * useless.
13042                                  */
13043                                 /* This is too slow for JIT compilation */
13044 #if 0
13045                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13046                                         MonoInst *ins;
13047                                         int def_index, call_index, ins_index;
13048                                         gboolean spilled = FALSE;
13049
13050                                         def_index = -1;
13051                                         call_index = -1;
13052                                         ins_index = 0;
13053                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13054                                                 const char *spec = INS_INFO (ins->opcode);
13055
13056                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13057                                                         def_index = ins_index;
13058
13059                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13060                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13061                                                         if (call_index > def_index) {
13062                                                                 spilled = TRUE;
13063                                                                 break;
13064                                                         }
13065                                                 }
13066
13067                                                 if (MONO_IS_CALL (ins))
13068                                                         call_index = ins_index;
13069
13070                                                 ins_index ++;
13071                                         }
13072
13073                                         if (spilled)
13074                                                 break;
13075                                 }
13076 #endif
13077
13078                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13079                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13080                                 var->flags |= MONO_INST_IS_DEAD;
13081                                 cfg->vreg_to_inst [var->dreg] = NULL;
13082                         }
13083                         break;
13084                 }
13085         }
13086
13087         /* 
13088          * Compress the varinfo and vars tables so the liveness computation is faster and
13089          * takes up less space.
13090          */
13091         pos = 0;
13092         for (i = 0; i < cfg->num_varinfo; ++i) {
13093                 MonoInst *var = cfg->varinfo [i];
13094                 if (pos < i && cfg->locals_start == i)
13095                         cfg->locals_start = pos;
13096                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13097                         if (pos < i) {
13098                                 cfg->varinfo [pos] = cfg->varinfo [i];
13099                                 cfg->varinfo [pos]->inst_c0 = pos;
13100                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13101                                 cfg->vars [pos].idx = pos;
13102 #if SIZEOF_REGISTER == 4
13103                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13104                                         /* Modify the two component vars too */
13105                                         MonoInst *var1;
13106
13107                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13108                                         var1->inst_c0 = pos;
13109                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13110                                         var1->inst_c0 = pos;
13111                                 }
13112 #endif
13113                         }
13114                         pos ++;
13115                 }
13116         }
13117         cfg->num_varinfo = pos;
13118         if (cfg->locals_start > cfg->num_varinfo)
13119                 cfg->locals_start = cfg->num_varinfo;
13120 }
13121
13122 /**
13123  * mono_spill_global_vars:
13124  *
13125  *   Generate spill code for variables which are not allocated to registers, 
13126  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13127  * code is generated which could be optimized by the local optimization passes.
13128  */
13129 void
13130 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13131 {
13132         MonoBasicBlock *bb;
13133         char spec2 [16];
13134         int orig_next_vreg;
13135         guint32 *vreg_to_lvreg;
13136         guint32 *lvregs;
13137         guint32 i, lvregs_len;
13138         gboolean dest_has_lvreg = FALSE;
13139         guint32 stacktypes [128];
13140         MonoInst **live_range_start, **live_range_end;
13141         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13142         int *gsharedvt_vreg_to_idx = NULL;
13143
13144         *need_local_opts = FALSE;
13145
13146         memset (spec2, 0, sizeof (spec2));
13147
13148         /* FIXME: Move this function to mini.c */
13149         stacktypes ['i'] = STACK_PTR;
13150         stacktypes ['l'] = STACK_I8;
13151         stacktypes ['f'] = STACK_R8;
13152 #ifdef MONO_ARCH_SIMD_INTRINSICS
13153         stacktypes ['x'] = STACK_VTYPE;
13154 #endif
13155
13156 #if SIZEOF_REGISTER == 4
13157         /* Create MonoInsts for longs */
13158         for (i = 0; i < cfg->num_varinfo; i++) {
13159                 MonoInst *ins = cfg->varinfo [i];
13160
13161                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13162                         switch (ins->type) {
13163                         case STACK_R8:
13164                         case STACK_I8: {
13165                                 MonoInst *tree;
13166
13167                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13168                                         break;
13169
13170                                 g_assert (ins->opcode == OP_REGOFFSET);
13171
13172                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13173                                 g_assert (tree);
13174                                 tree->opcode = OP_REGOFFSET;
13175                                 tree->inst_basereg = ins->inst_basereg;
13176                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13177
13178                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13179                                 g_assert (tree);
13180                                 tree->opcode = OP_REGOFFSET;
13181                                 tree->inst_basereg = ins->inst_basereg;
13182                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13183                                 break;
13184                         }
13185                         default:
13186                                 break;
13187                         }
13188                 }
13189         }
13190 #endif
13191
13192         if (cfg->compute_gc_maps) {
13193                 /* registers need liveness info even for !non refs */
13194                 for (i = 0; i < cfg->num_varinfo; i++) {
13195                         MonoInst *ins = cfg->varinfo [i];
13196
13197                         if (ins->opcode == OP_REGVAR)
13198                                 ins->flags |= MONO_INST_GC_TRACK;
13199                 }
13200         }
13201
13202         if (cfg->gsharedvt) {
13203                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13204
13205                 for (i = 0; i < cfg->num_varinfo; ++i) {
13206                         MonoInst *ins = cfg->varinfo [i];
13207                         int idx;
13208
13209                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13210                                 if (i >= cfg->locals_start) {
13211                                         /* Local */
13212                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13213                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13214                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13215                                         ins->inst_imm = idx;
13216                                 } else {
13217                                         /* Arg */
13218                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13219                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13220                                 }
13221                         }
13222                 }
13223         }
13224                 
13225         /* FIXME: widening and truncation */
13226
13227         /*
13228          * As an optimization, when a variable allocated to the stack is first loaded into 
13229          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13230          * the variable again.
13231          */
13232         orig_next_vreg = cfg->next_vreg;
13233         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13234         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13235         lvregs_len = 0;
13236
13237         /* 
13238          * These arrays contain the first and last instructions accessing a given
13239          * variable.
13240          * Since we emit bblocks in the same order we process them here, and we
13241          * don't split live ranges, these will precisely describe the live range of
13242          * the variable, i.e. the instruction range where a valid value can be found
13243          * in the variables location.
13244          * The live range is computed using the liveness info computed by the liveness pass.
13245          * We can't use vmv->range, since that is an abstract live range, and we need
13246          * one which is instruction precise.
13247          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13248          */
13249         /* FIXME: Only do this if debugging info is requested */
13250         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13251         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13252         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13253         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13254         
13255         /* Add spill loads/stores */
13256         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13257                 MonoInst *ins;
13258
13259                 if (cfg->verbose_level > 2)
13260                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13261
13262                 /* Clear vreg_to_lvreg array */
13263                 for (i = 0; i < lvregs_len; i++)
13264                         vreg_to_lvreg [lvregs [i]] = 0;
13265                 lvregs_len = 0;
13266
13267                 cfg->cbb = bb;
13268                 MONO_BB_FOR_EACH_INS (bb, ins) {
13269                         const char *spec = INS_INFO (ins->opcode);
13270                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13271                         gboolean store, no_lvreg;
13272                         int sregs [MONO_MAX_SRC_REGS];
13273
13274                         if (G_UNLIKELY (cfg->verbose_level > 2))
13275                                 mono_print_ins (ins);
13276
13277                         if (ins->opcode == OP_NOP)
13278                                 continue;
13279
13280                         /* 
13281                          * We handle LDADDR here as well, since it can only be decomposed
13282                          * when variable addresses are known.
13283                          */
13284                         if (ins->opcode == OP_LDADDR) {
13285                                 MonoInst *var = ins->inst_p0;
13286
13287                                 if (var->opcode == OP_VTARG_ADDR) {
13288                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13289                                         MonoInst *vtaddr = var->inst_left;
13290                                         if (vtaddr->opcode == OP_REGVAR) {
13291                                                 ins->opcode = OP_MOVE;
13292                                                 ins->sreg1 = vtaddr->dreg;
13293                                         }
13294                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13295                                                 ins->opcode = OP_LOAD_MEMBASE;
13296                                                 ins->inst_basereg = vtaddr->inst_basereg;
13297                                                 ins->inst_offset = vtaddr->inst_offset;
13298                                         } else
13299                                                 NOT_IMPLEMENTED;
13300                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13301                                         /* gsharedvt arg passed by ref */
13302                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13303
13304                                         ins->opcode = OP_LOAD_MEMBASE;
13305                                         ins->inst_basereg = var->inst_basereg;
13306                                         ins->inst_offset = var->inst_offset;
13307                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13308                                         MonoInst *load, *load2, *load3;
13309                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13310                                         int reg1, reg2, reg3;
13311                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13312                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13313
13314                                         /*
13315                                          * gsharedvt local.
13316                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13317                                          */
13318
13319                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13320
13321                                         g_assert (info_var);
13322                                         g_assert (locals_var);
13323
13324                                         /* Mark the instruction used to compute the locals var as used */
13325                                         cfg->gsharedvt_locals_var_ins = NULL;
13326
13327                                         /* Load the offset */
13328                                         if (info_var->opcode == OP_REGOFFSET) {
13329                                                 reg1 = alloc_ireg (cfg);
13330                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13331                                         } else if (info_var->opcode == OP_REGVAR) {
13332                                                 load = NULL;
13333                                                 reg1 = info_var->dreg;
13334                                         } else {
13335                                                 g_assert_not_reached ();
13336                                         }
13337                                         reg2 = alloc_ireg (cfg);
13338                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13339                                         /* Load the locals area address */
13340                                         reg3 = alloc_ireg (cfg);
13341                                         if (locals_var->opcode == OP_REGOFFSET) {
13342                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13343                                         } else if (locals_var->opcode == OP_REGVAR) {
13344                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13345                                         } else {
13346                                                 g_assert_not_reached ();
13347                                         }
13348                                         /* Compute the address */
13349                                         ins->opcode = OP_PADD;
13350                                         ins->sreg1 = reg3;
13351                                         ins->sreg2 = reg2;
13352
13353                                         mono_bblock_insert_before_ins (bb, ins, load3);
13354                                         mono_bblock_insert_before_ins (bb, load3, load2);
13355                                         if (load)
13356                                                 mono_bblock_insert_before_ins (bb, load2, load);
13357                                 } else {
13358                                         g_assert (var->opcode == OP_REGOFFSET);
13359
13360                                         ins->opcode = OP_ADD_IMM;
13361                                         ins->sreg1 = var->inst_basereg;
13362                                         ins->inst_imm = var->inst_offset;
13363                                 }
13364
13365                                 *need_local_opts = TRUE;
13366                                 spec = INS_INFO (ins->opcode);
13367                         }
13368
13369                         if (ins->opcode < MONO_CEE_LAST) {
13370                                 mono_print_ins (ins);
13371                                 g_assert_not_reached ();
13372                         }
13373
13374                         /*
13375                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13376                          * src register.
13377                          * FIXME:
13378                          */
13379                         if (MONO_IS_STORE_MEMBASE (ins)) {
13380                                 tmp_reg = ins->dreg;
13381                                 ins->dreg = ins->sreg2;
13382                                 ins->sreg2 = tmp_reg;
13383                                 store = TRUE;
13384
13385                                 spec2 [MONO_INST_DEST] = ' ';
13386                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13387                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13388                                 spec2 [MONO_INST_SRC3] = ' ';
13389                                 spec = spec2;
13390                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13391                                 g_assert_not_reached ();
13392                         else
13393                                 store = FALSE;
13394                         no_lvreg = FALSE;
13395
13396                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13397                                 printf ("\t %.3s %d", spec, ins->dreg);
13398                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13399                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13400                                         printf (" %d", sregs [srcindex]);
13401                                 printf ("\n");
13402                         }
13403
13404                         /***************/
13405                         /*    DREG     */
13406                         /***************/
13407                         regtype = spec [MONO_INST_DEST];
13408                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13409                         prev_dreg = -1;
13410
13411                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13412                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13413                                 MonoInst *store_ins;
13414                                 int store_opcode;
13415                                 MonoInst *def_ins = ins;
13416                                 int dreg = ins->dreg; /* The original vreg */
13417
13418                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13419
13420                                 if (var->opcode == OP_REGVAR) {
13421                                         ins->dreg = var->dreg;
13422                                 } 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)) {
13423                                         /* 
13424                                          * Instead of emitting a load+store, use a _membase opcode.
13425                                          */
13426                                         g_assert (var->opcode == OP_REGOFFSET);
13427                                         if (ins->opcode == OP_MOVE) {
13428                                                 NULLIFY_INS (ins);
13429                                                 def_ins = NULL;
13430                                         } else {
13431                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13432                                                 ins->inst_basereg = var->inst_basereg;
13433                                                 ins->inst_offset = var->inst_offset;
13434                                                 ins->dreg = -1;
13435                                         }
13436                                         spec = INS_INFO (ins->opcode);
13437                                 } else {
13438                                         guint32 lvreg;
13439
13440                                         g_assert (var->opcode == OP_REGOFFSET);
13441
13442                                         prev_dreg = ins->dreg;
13443
13444                                         /* Invalidate any previous lvreg for this vreg */
13445                                         vreg_to_lvreg [ins->dreg] = 0;
13446
13447                                         lvreg = 0;
13448
13449                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13450                                                 regtype = 'l';
13451                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13452                                         }
13453
13454                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13455
13456 #if SIZEOF_REGISTER != 8
13457                                         if (regtype == 'l') {
13458                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13459                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13460                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13461                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13462                                                 def_ins = store_ins;
13463                                         }
13464                                         else
13465 #endif
13466                                         {
13467                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13468
13469                                                 /* Try to fuse the store into the instruction itself */
13470                                                 /* FIXME: Add more instructions */
13471                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13472                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13473                                                         ins->inst_imm = ins->inst_c0;
13474                                                         ins->inst_destbasereg = var->inst_basereg;
13475                                                         ins->inst_offset = var->inst_offset;
13476                                                         spec = INS_INFO (ins->opcode);
13477                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13478                                                         ins->opcode = store_opcode;
13479                                                         ins->inst_destbasereg = var->inst_basereg;
13480                                                         ins->inst_offset = var->inst_offset;
13481
13482                                                         no_lvreg = TRUE;
13483
13484                                                         tmp_reg = ins->dreg;
13485                                                         ins->dreg = ins->sreg2;
13486                                                         ins->sreg2 = tmp_reg;
13487                                                         store = TRUE;
13488
13489                                                         spec2 [MONO_INST_DEST] = ' ';
13490                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13491                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13492                                                         spec2 [MONO_INST_SRC3] = ' ';
13493                                                         spec = spec2;
13494                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13495                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13496                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13497                                                         ins->dreg = -1;
13498                                                         ins->inst_basereg = var->inst_basereg;
13499                                                         ins->inst_offset = var->inst_offset;
13500                                                         spec = INS_INFO (ins->opcode);
13501                                                 } else {
13502                                                         /* printf ("INS: "); mono_print_ins (ins); */
13503                                                         /* Create a store instruction */
13504                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13505
13506                                                         /* Insert it after the instruction */
13507                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13508
13509                                                         def_ins = store_ins;
13510
13511                                                         /* 
13512                                                          * We can't assign ins->dreg to var->dreg here, since the
13513                                                          * sregs could use it. So set a flag, and do it after
13514                                                          * the sregs.
13515                                                          */
13516                                                         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)))
13517                                                                 dest_has_lvreg = TRUE;
13518                                                 }
13519                                         }
13520                                 }
13521
13522                                 if (def_ins && !live_range_start [dreg]) {
13523                                         live_range_start [dreg] = def_ins;
13524                                         live_range_start_bb [dreg] = bb;
13525                                 }
13526
13527                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13528                                         MonoInst *tmp;
13529
13530                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13531                                         tmp->inst_c1 = dreg;
13532                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13533                                 }
13534                         }
13535
13536                         /************/
13537                         /*  SREGS   */
13538                         /************/
13539                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13540                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13541                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13542                                 sreg = sregs [srcindex];
13543
13544                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13545                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13546                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13547                                         MonoInst *use_ins = ins;
13548                                         MonoInst *load_ins;
13549                                         guint32 load_opcode;
13550
13551                                         if (var->opcode == OP_REGVAR) {
13552                                                 sregs [srcindex] = var->dreg;
13553                                                 //mono_inst_set_src_registers (ins, sregs);
13554                                                 live_range_end [sreg] = use_ins;
13555                                                 live_range_end_bb [sreg] = bb;
13556
13557                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13558                                                         MonoInst *tmp;
13559
13560                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13561                                                         /* var->dreg is a hreg */
13562                                                         tmp->inst_c1 = sreg;
13563                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13564                                                 }
13565
13566                                                 continue;
13567                                         }
13568
13569                                         g_assert (var->opcode == OP_REGOFFSET);
13570                                                 
13571                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13572
13573                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13574
13575                                         if (vreg_to_lvreg [sreg]) {
13576                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13577
13578                                                 /* The variable is already loaded to an lvreg */
13579                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13580                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13581                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13582                                                 //mono_inst_set_src_registers (ins, sregs);
13583                                                 continue;
13584                                         }
13585
13586                                         /* Try to fuse the load into the instruction */
13587                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13588                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13589                                                 sregs [0] = var->inst_basereg;
13590                                                 //mono_inst_set_src_registers (ins, sregs);
13591                                                 ins->inst_offset = var->inst_offset;
13592                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13593                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13594                                                 sregs [1] = var->inst_basereg;
13595                                                 //mono_inst_set_src_registers (ins, sregs);
13596                                                 ins->inst_offset = var->inst_offset;
13597                                         } else {
13598                                                 if (MONO_IS_REAL_MOVE (ins)) {
13599                                                         ins->opcode = OP_NOP;
13600                                                         sreg = ins->dreg;
13601                                                 } else {
13602                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13603
13604                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13605
13606                                                         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) {
13607                                                                 if (var->dreg == prev_dreg) {
13608                                                                         /*
13609                                                                          * sreg refers to the value loaded by the load
13610                                                                          * emitted below, but we need to use ins->dreg
13611                                                                          * since it refers to the store emitted earlier.
13612                                                                          */
13613                                                                         sreg = ins->dreg;
13614                                                                 }
13615                                                                 g_assert (sreg != -1);
13616                                                                 vreg_to_lvreg [var->dreg] = sreg;
13617                                                                 g_assert (lvregs_len < 1024);
13618                                                                 lvregs [lvregs_len ++] = var->dreg;
13619                                                         }
13620                                                 }
13621
13622                                                 sregs [srcindex] = sreg;
13623                                                 //mono_inst_set_src_registers (ins, sregs);
13624
13625 #if SIZEOF_REGISTER != 8
13626                                                 if (regtype == 'l') {
13627                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13628                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13629                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13630                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13631                                                         use_ins = load_ins;
13632                                                 }
13633                                                 else
13634 #endif
13635                                                 {
13636 #if SIZEOF_REGISTER == 4
13637                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13638 #endif
13639                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13640                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13641                                                         use_ins = load_ins;
13642                                                 }
13643                                         }
13644
13645                                         if (var->dreg < orig_next_vreg) {
13646                                                 live_range_end [var->dreg] = use_ins;
13647                                                 live_range_end_bb [var->dreg] = bb;
13648                                         }
13649
13650                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13651                                                 MonoInst *tmp;
13652
13653                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13654                                                 tmp->inst_c1 = var->dreg;
13655                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13656                                         }
13657                                 }
13658                         }
13659                         mono_inst_set_src_registers (ins, sregs);
13660
13661                         if (dest_has_lvreg) {
13662                                 g_assert (ins->dreg != -1);
13663                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13664                                 g_assert (lvregs_len < 1024);
13665                                 lvregs [lvregs_len ++] = prev_dreg;
13666                                 dest_has_lvreg = FALSE;
13667                         }
13668
13669                         if (store) {
13670                                 tmp_reg = ins->dreg;
13671                                 ins->dreg = ins->sreg2;
13672                                 ins->sreg2 = tmp_reg;
13673                         }
13674
13675                         if (MONO_IS_CALL (ins)) {
13676                                 /* Clear vreg_to_lvreg array */
13677                                 for (i = 0; i < lvregs_len; i++)
13678                                         vreg_to_lvreg [lvregs [i]] = 0;
13679                                 lvregs_len = 0;
13680                         } else if (ins->opcode == OP_NOP) {
13681                                 ins->dreg = -1;
13682                                 MONO_INST_NULLIFY_SREGS (ins);
13683                         }
13684
13685                         if (cfg->verbose_level > 2)
13686                                 mono_print_ins_index (1, ins);
13687                 }
13688
13689                 /* Extend the live range based on the liveness info */
13690                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13691                         for (i = 0; i < cfg->num_varinfo; i ++) {
13692                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13693
13694                                 if (vreg_is_volatile (cfg, vi->vreg))
13695                                         /* The liveness info is incomplete */
13696                                         continue;
13697
13698                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13699                                         /* Live from at least the first ins of this bb */
13700                                         live_range_start [vi->vreg] = bb->code;
13701                                         live_range_start_bb [vi->vreg] = bb;
13702                                 }
13703
13704                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13705                                         /* Live at least until the last ins of this bb */
13706                                         live_range_end [vi->vreg] = bb->last_ins;
13707                                         live_range_end_bb [vi->vreg] = bb;
13708                                 }
13709                         }
13710                 }
13711         }
13712         
13713 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13714         /*
13715          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13716          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13717          */
13718         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13719                 for (i = 0; i < cfg->num_varinfo; ++i) {
13720                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13721                         MonoInst *ins;
13722
13723                         if (live_range_start [vreg]) {
13724                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13725                                 ins->inst_c0 = i;
13726                                 ins->inst_c1 = vreg;
13727                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13728                         }
13729                         if (live_range_end [vreg]) {
13730                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13731                                 ins->inst_c0 = i;
13732                                 ins->inst_c1 = vreg;
13733                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13734                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13735                                 else
13736                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13737                         }
13738                 }
13739         }
13740 #endif
13741
13742         if (cfg->gsharedvt_locals_var_ins) {
13743                 /* Nullify if unused */
13744                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13745                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13746         }
13747
13748         g_free (live_range_start);
13749         g_free (live_range_end);
13750         g_free (live_range_start_bb);
13751         g_free (live_range_end_bb);
13752 }
13753
13754 /**
13755  * FIXME:
13756  * - use 'iadd' instead of 'int_add'
13757  * - handling ovf opcodes: decompose in method_to_ir.
13758  * - unify iregs/fregs
13759  *   -> partly done, the missing parts are:
13760  *   - a more complete unification would involve unifying the hregs as well, so
13761  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13762  *     would no longer map to the machine hregs, so the code generators would need to
13763  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13764  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13765  *     fp/non-fp branches speeds it up by about 15%.
13766  * - use sext/zext opcodes instead of shifts
13767  * - add OP_ICALL
13768  * - get rid of TEMPLOADs if possible and use vregs instead
13769  * - clean up usage of OP_P/OP_ opcodes
13770  * - cleanup usage of DUMMY_USE
13771  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13772  *   stack
13773  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13774  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13775  * - make sure handle_stack_args () is called before the branch is emitted
13776  * - when the new IR is done, get rid of all unused stuff
13777  * - COMPARE/BEQ as separate instructions or unify them ?
13778  *   - keeping them separate allows specialized compare instructions like
13779  *     compare_imm, compare_membase
13780  *   - most back ends unify fp compare+branch, fp compare+ceq
13781  * - integrate mono_save_args into inline_method
13782  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13783  * - handle long shift opts on 32 bit platforms somehow: they require 
13784  *   3 sregs (2 for arg1 and 1 for arg2)
13785  * - make byref a 'normal' type.
13786  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13787  *   variable if needed.
13788  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13789  *   like inline_method.
13790  * - remove inlining restrictions
13791  * - fix LNEG and enable cfold of INEG
13792  * - generalize x86 optimizations like ldelema as a peephole optimization
13793  * - add store_mem_imm for amd64
13794  * - optimize the loading of the interruption flag in the managed->native wrappers
13795  * - avoid special handling of OP_NOP in passes
13796  * - move code inserting instructions into one function/macro.
13797  * - try a coalescing phase after liveness analysis
13798  * - add float -> vreg conversion + local optimizations on !x86
13799  * - figure out how to handle decomposed branches during optimizations, ie.
13800  *   compare+branch, op_jump_table+op_br etc.
13801  * - promote RuntimeXHandles to vregs
13802  * - vtype cleanups:
13803  *   - add a NEW_VARLOADA_VREG macro
13804  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13805  *   accessing vtype fields.
13806  * - get rid of I8CONST on 64 bit platforms
13807  * - dealing with the increase in code size due to branches created during opcode
13808  *   decomposition:
13809  *   - use extended basic blocks
13810  *     - all parts of the JIT
13811  *     - handle_global_vregs () && local regalloc
13812  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13813  * - sources of increase in code size:
13814  *   - vtypes
13815  *   - long compares
13816  *   - isinst and castclass
13817  *   - lvregs not allocated to global registers even if used multiple times
13818  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13819  *   meaningful.
13820  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13821  * - add all micro optimizations from the old JIT
13822  * - put tree optimizations into the deadce pass
13823  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13824  *   specific function.
13825  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13826  *   fcompare + branchCC.
13827  * - create a helper function for allocating a stack slot, taking into account 
13828  *   MONO_CFG_HAS_SPILLUP.
13829  * - merge r68207.
13830  * - merge the ia64 switch changes.
13831  * - optimize mono_regstate2_alloc_int/float.
13832  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13833  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13834  *   parts of the tree could be separated by other instructions, killing the tree
13835  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13836  *   instructions if the result of the load is used multiple times ?
13837  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13838  * - LAST MERGE: 108395.
13839  * - when returning vtypes in registers, generate IR and append it to the end of the
13840  *   last bb instead of doing it in the epilog.
13841  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13842  */
13843
13844 /*
13845
13846 NOTES
13847 -----
13848
13849 - When to decompose opcodes:
13850   - earlier: this makes some optimizations hard to implement, since the low level IR
13851   no longer contains the neccessary information. But it is easier to do.
13852   - later: harder to implement, enables more optimizations.
13853 - Branches inside bblocks:
13854   - created when decomposing complex opcodes. 
13855     - branches to another bblock: harmless, but not tracked by the branch 
13856       optimizations, so need to branch to a label at the start of the bblock.
13857     - branches to inside the same bblock: very problematic, trips up the local
13858       reg allocator. Can be fixed by spitting the current bblock, but that is a
13859       complex operation, since some local vregs can become global vregs etc.
13860 - Local/global vregs:
13861   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13862     local register allocator.
13863   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13864     structure, created by mono_create_var (). Assigned to hregs or the stack by
13865     the global register allocator.
13866 - When to do optimizations like alu->alu_imm:
13867   - earlier -> saves work later on since the IR will be smaller/simpler
13868   - later -> can work on more instructions
13869 - Handling of valuetypes:
13870   - When a vtype is pushed on the stack, a new temporary is created, an 
13871     instruction computing its address (LDADDR) is emitted and pushed on
13872     the stack. Need to optimize cases when the vtype is used immediately as in
13873     argument passing, stloc etc.
13874 - Instead of the to_end stuff in the old JIT, simply call the function handling
13875   the values on the stack before emitting the last instruction of the bb.
13876 */
13877
13878 #endif /* DISABLE_JIT */