Fix to UriTemplate.Match to properly handle query parameters without a value. No...
[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
3891                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3892
3893                 if (cfg->opt & MONO_OPT_SHARED)
3894                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3895                 else
3896                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3897                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3898
3899                 if (cfg->opt & MONO_OPT_SHARED) {
3900                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3901                         iargs [1] = data;
3902                         alloc_ftn = mono_object_new;
3903                 } else {
3904                         iargs [0] = data;
3905                         alloc_ftn = mono_object_new_specific;
3906                 }
3907
3908                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3909                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3910
3911                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3912         }
3913
3914         if (cfg->opt & MONO_OPT_SHARED) {
3915                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3916                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3917
3918                 alloc_ftn = mono_object_new;
3919         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3920                 /* This happens often in argument checking code, eg. throw new FooException... */
3921                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3922                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3923                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3924         } else {
3925                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3926                 MonoMethod *managed_alloc = NULL;
3927                 gboolean pass_lw;
3928
3929                 if (!vtable) {
3930                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3931                         cfg->exception_ptr = klass;
3932                         return NULL;
3933                 }
3934
3935 #ifndef MONO_CROSS_COMPILE
3936                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3937 #endif
3938
3939                 if (managed_alloc) {
3940                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3941                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3942                 }
3943                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3944                 if (pass_lw) {
3945                         guint32 lw = vtable->klass->instance_size;
3946                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3947                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3948                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3949                 }
3950                 else {
3951                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3952                 }
3953         }
3954
3955         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3956 }
3957         
3958 /*
3959  * Returns NULL and set the cfg exception on error.
3960  */     
3961 static MonoInst*
3962 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3963 {
3964         MonoInst *alloc, *ins;
3965
3966         *out_cbb = cfg->cbb;
3967
3968         if (mono_class_is_nullable (klass)) {
3969                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3970
3971                 if (context_used) {
3972                         /* FIXME: What if the class is shared?  We might not
3973                            have to get the method address from the RGCTX. */
3974                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3975                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3976                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3977
3978                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3979                 } else {
3980                         gboolean pass_vtable, pass_mrgctx;
3981                         MonoInst *rgctx_arg = NULL;
3982
3983                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3984                         g_assert (!pass_mrgctx);
3985
3986                         if (pass_vtable) {
3987                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3988
3989                                 g_assert (vtable);
3990                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3991                         }
3992
3993                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3994                 }
3995         }
3996
3997         if (mini_is_gsharedvt_klass (cfg, klass)) {
3998                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3999                 MonoInst *res, *is_ref, *src_var, *addr;
4000                 int addr_reg, dreg;
4001
4002                 dreg = alloc_ireg (cfg);
4003
4004                 NEW_BBLOCK (cfg, is_ref_bb);
4005                 NEW_BBLOCK (cfg, is_nullable_bb);
4006                 NEW_BBLOCK (cfg, end_bb);
4007                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4008                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
4009                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4010
4011                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
4012                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4013
4014                 /* Non-ref case */
4015                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4016                 if (!alloc)
4017                         return NULL;
4018                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4019                 ins->opcode = OP_STOREV_MEMBASE;
4020
4021                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4022                 res->type = STACK_OBJ;
4023                 res->klass = klass;
4024                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4025                 
4026                 /* Ref case */
4027                 MONO_START_BB (cfg, is_ref_bb);
4028                 addr_reg = alloc_ireg (cfg);
4029
4030                 /* val is a vtype, so has to load the value manually */
4031                 src_var = get_vreg_to_inst (cfg, val->dreg);
4032                 if (!src_var)
4033                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4034                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4035                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4036                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4037
4038                 /* Nullable case */
4039                 MONO_START_BB (cfg, is_nullable_bb);
4040
4041                 {
4042                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4043                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4044                         MonoInst *box_call;
4045                         MonoMethodSignature *box_sig;
4046
4047                         /*
4048                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4049                          * construct that method at JIT time, so have to do things by hand.
4050                          */
4051                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4052                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4053                         box_sig->param_count = 1;
4054                         box_sig->params [0] = &klass->byval_arg;
4055                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4056                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4057                         res->type = STACK_OBJ;
4058                         res->klass = klass;
4059                 }
4060
4061                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4062
4063                 MONO_START_BB (cfg, end_bb);
4064
4065                 *out_cbb = cfg->cbb;
4066
4067                 return res;
4068         } else {
4069                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4070                 if (!alloc)
4071                         return NULL;
4072
4073                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4074                 return alloc;
4075         }
4076 }
4077
4078
4079 static gboolean
4080 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4081 {
4082         int i;
4083         MonoGenericContainer *container;
4084         MonoGenericInst *ginst;
4085
4086         if (klass->generic_class) {
4087                 container = klass->generic_class->container_class->generic_container;
4088                 ginst = klass->generic_class->context.class_inst;
4089         } else if (klass->generic_container && context_used) {
4090                 container = klass->generic_container;
4091                 ginst = container->context.class_inst;
4092         } else {
4093                 return FALSE;
4094         }
4095
4096         for (i = 0; i < container->type_argc; ++i) {
4097                 MonoType *type;
4098                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4099                         continue;
4100                 type = ginst->type_argv [i];
4101                 if (mini_type_is_reference (cfg, type))
4102                         return TRUE;
4103         }
4104         return FALSE;
4105 }
4106
4107 #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)
4108
4109 static MonoInst*
4110 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args, MonoBasicBlock **out_bblock)
4111 {
4112         MonoMethod *mono_castclass;
4113         MonoInst *res;
4114
4115         mono_castclass = mono_marshal_get_castclass_with_cache ();
4116
4117         save_cast_details (cfg, klass, args [0]->dreg, TRUE, out_bblock);
4118         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4119         reset_cast_details (cfg);
4120         *out_bblock = cfg->cbb;
4121
4122         return res;
4123 }
4124
4125 static MonoInst*
4126 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass, MonoBasicBlock **out_bblock)
4127 {
4128         MonoInst *args [3];
4129         int idx;
4130
4131         /* obj */
4132         args [0] = obj;
4133
4134         /* klass */
4135         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4136
4137         /* inline cache*/
4138         if (cfg->compile_aot) {
4139                 /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4140                 cfg->castclass_cache_index ++;
4141                 idx = (cfg->method_index << 16) | cfg->castclass_cache_index;
4142                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4143         } else {
4144                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
4145         }
4146
4147         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4148
4149         return emit_castclass_with_cache (cfg, klass, args, out_bblock);
4150 }
4151
4152 /*
4153  * Returns NULL and set the cfg exception on error.
4154  */
4155 static MonoInst*
4156 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, MonoBasicBlock **out_bb, int *inline_costs)
4157 {
4158         MonoBasicBlock *is_null_bb;
4159         int obj_reg = src->dreg;
4160         int vtable_reg = alloc_preg (cfg);
4161         int context_used;
4162         MonoInst *klass_inst = NULL, *res;
4163         MonoBasicBlock *bblock;
4164
4165         *out_bb = cfg->cbb;
4166
4167         context_used = mini_class_check_context_used (cfg, klass);
4168
4169         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4170                 res = emit_castclass_with_cache_nonshared (cfg, src, klass, &bblock);
4171                 (*inline_costs) += 2;
4172                 *out_bb = cfg->cbb;
4173                 return res;
4174         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4175                 MonoMethod *mono_castclass;
4176                 MonoInst *iargs [1];
4177                 int costs;
4178
4179                 mono_castclass = mono_marshal_get_castclass (klass); 
4180                 iargs [0] = src;
4181                                 
4182                 save_cast_details (cfg, klass, src->dreg, TRUE, &bblock);
4183                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4184                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
4185                 reset_cast_details (cfg);
4186                 CHECK_CFG_EXCEPTION;
4187                 g_assert (costs > 0);
4188                                 
4189                 cfg->real_offset += 5;
4190
4191                 (*inline_costs) += costs;
4192
4193                 *out_bb = cfg->cbb;
4194                 return src;
4195         }
4196
4197         if (context_used) {
4198                 MonoInst *args [3];
4199
4200                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4201                         MonoInst *cache_ins;
4202
4203                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4204
4205                         /* obj */
4206                         args [0] = src;
4207
4208                         /* klass - it's the second element of the cache entry*/
4209                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4210
4211                         /* cache */
4212                         args [2] = cache_ins;
4213
4214                         return emit_castclass_with_cache (cfg, klass, args, out_bb);
4215                 }
4216
4217                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4218         }
4219
4220         NEW_BBLOCK (cfg, is_null_bb);
4221
4222         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4223         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4224
4225         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4226
4227         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4228                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4229                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4230         } else {
4231                 int klass_reg = alloc_preg (cfg);
4232
4233                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4234
4235                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4236                         /* the remoting code is broken, access the class for now */
4237                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4238                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4239                                 if (!vt) {
4240                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4241                                         cfg->exception_ptr = klass;
4242                                         return NULL;
4243                                 }
4244                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4245                         } else {
4246                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4247                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4248                         }
4249                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4250                 } else {
4251                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4252                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4253                 }
4254         }
4255
4256         MONO_START_BB (cfg, is_null_bb);
4257
4258         reset_cast_details (cfg);
4259
4260         *out_bb = cfg->cbb;
4261
4262         return src;
4263
4264 exception_exit:
4265         return NULL;
4266 }
4267
4268 /*
4269  * Returns NULL and set the cfg exception on error.
4270  */
4271 static MonoInst*
4272 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4273 {
4274         MonoInst *ins;
4275         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4276         int obj_reg = src->dreg;
4277         int vtable_reg = alloc_preg (cfg);
4278         int res_reg = alloc_ireg_ref (cfg);
4279         MonoInst *klass_inst = NULL;
4280
4281         if (context_used) {
4282                 MonoInst *args [3];
4283
4284                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4285                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4286                         MonoInst *cache_ins;
4287
4288                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4289
4290                         /* obj */
4291                         args [0] = src;
4292
4293                         /* klass - it's the second element of the cache entry*/
4294                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4295
4296                         /* cache */
4297                         args [2] = cache_ins;
4298
4299                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4300                 }
4301
4302                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4303         }
4304
4305         NEW_BBLOCK (cfg, is_null_bb);
4306         NEW_BBLOCK (cfg, false_bb);
4307         NEW_BBLOCK (cfg, end_bb);
4308
4309         /* Do the assignment at the beginning, so the other assignment can be if converted */
4310         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4311         ins->type = STACK_OBJ;
4312         ins->klass = klass;
4313
4314         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4315         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4316
4317         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4318
4319         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4320                 g_assert (!context_used);
4321                 /* the is_null_bb target simply copies the input register to the output */
4322                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4323         } else {
4324                 int klass_reg = alloc_preg (cfg);
4325
4326                 if (klass->rank) {
4327                         int rank_reg = alloc_preg (cfg);
4328                         int eclass_reg = alloc_preg (cfg);
4329
4330                         g_assert (!context_used);
4331                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4332                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4333                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4334                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4335                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4336                         if (klass->cast_class == mono_defaults.object_class) {
4337                                 int parent_reg = alloc_preg (cfg);
4338                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4339                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4340                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4341                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4342                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4343                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4344                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4345                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4346                         } else if (klass->cast_class == mono_defaults.enum_class) {
4347                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4348                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4349                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4350                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4351                         } else {
4352                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4353                                         /* Check that the object is a vector too */
4354                                         int bounds_reg = alloc_preg (cfg);
4355                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4356                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4357                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4358                                 }
4359
4360                                 /* the is_null_bb target simply copies the input register to the output */
4361                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4362                         }
4363                 } else if (mono_class_is_nullable (klass)) {
4364                         g_assert (!context_used);
4365                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4366                         /* the is_null_bb target simply copies the input register to the output */
4367                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4368                 } else {
4369                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4370                                 g_assert (!context_used);
4371                                 /* the remoting code is broken, access the class for now */
4372                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4373                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4374                                         if (!vt) {
4375                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4376                                                 cfg->exception_ptr = klass;
4377                                                 return NULL;
4378                                         }
4379                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4380                                 } else {
4381                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4382                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4383                                 }
4384                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4385                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4386                         } else {
4387                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4388                                 /* the is_null_bb target simply copies the input register to the output */
4389                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4390                         }
4391                 }
4392         }
4393
4394         MONO_START_BB (cfg, false_bb);
4395
4396         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4397         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4398
4399         MONO_START_BB (cfg, is_null_bb);
4400
4401         MONO_START_BB (cfg, end_bb);
4402
4403         return ins;
4404 }
4405
4406 static MonoInst*
4407 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4408 {
4409         /* This opcode takes as input an object reference and a class, and returns:
4410         0) if the object is an instance of the class,
4411         1) if the object is not instance of the class,
4412         2) if the object is a proxy whose type cannot be determined */
4413
4414         MonoInst *ins;
4415 #ifndef DISABLE_REMOTING
4416         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4417 #else
4418         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4419 #endif
4420         int obj_reg = src->dreg;
4421         int dreg = alloc_ireg (cfg);
4422         int tmp_reg;
4423 #ifndef DISABLE_REMOTING
4424         int klass_reg = alloc_preg (cfg);
4425 #endif
4426
4427         NEW_BBLOCK (cfg, true_bb);
4428         NEW_BBLOCK (cfg, false_bb);
4429         NEW_BBLOCK (cfg, end_bb);
4430 #ifndef DISABLE_REMOTING
4431         NEW_BBLOCK (cfg, false2_bb);
4432         NEW_BBLOCK (cfg, no_proxy_bb);
4433 #endif
4434
4435         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4436         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4437
4438         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4439 #ifndef DISABLE_REMOTING
4440                 NEW_BBLOCK (cfg, interface_fail_bb);
4441 #endif
4442
4443                 tmp_reg = alloc_preg (cfg);
4444                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4445 #ifndef DISABLE_REMOTING
4446                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4447                 MONO_START_BB (cfg, interface_fail_bb);
4448                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4449                 
4450                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4451
4452                 tmp_reg = alloc_preg (cfg);
4453                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4454                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4455                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4456 #else
4457                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4458 #endif
4459         } else {
4460 #ifndef DISABLE_REMOTING
4461                 tmp_reg = alloc_preg (cfg);
4462                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4463                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4464
4465                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4466                 tmp_reg = alloc_preg (cfg);
4467                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4468                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4469
4470                 tmp_reg = alloc_preg (cfg);             
4471                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4472                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4473                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4474                 
4475                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4476                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4477
4478                 MONO_START_BB (cfg, no_proxy_bb);
4479
4480                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4481 #else
4482                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4483 #endif
4484         }
4485
4486         MONO_START_BB (cfg, false_bb);
4487
4488         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4489         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4490
4491 #ifndef DISABLE_REMOTING
4492         MONO_START_BB (cfg, false2_bb);
4493
4494         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4495         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4496 #endif
4497
4498         MONO_START_BB (cfg, true_bb);
4499
4500         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4501
4502         MONO_START_BB (cfg, end_bb);
4503
4504         /* FIXME: */
4505         MONO_INST_NEW (cfg, ins, OP_ICONST);
4506         ins->dreg = dreg;
4507         ins->type = STACK_I4;
4508
4509         return ins;
4510 }
4511
4512 static MonoInst*
4513 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4514 {
4515         /* This opcode takes as input an object reference and a class, and returns:
4516         0) if the object is an instance of the class,
4517         1) if the object is a proxy whose type cannot be determined
4518         an InvalidCastException exception is thrown otherwhise*/
4519         
4520         MonoInst *ins;
4521 #ifndef DISABLE_REMOTING
4522         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4523 #else
4524         MonoBasicBlock *ok_result_bb;
4525 #endif
4526         int obj_reg = src->dreg;
4527         int dreg = alloc_ireg (cfg);
4528         int tmp_reg = alloc_preg (cfg);
4529
4530 #ifndef DISABLE_REMOTING
4531         int klass_reg = alloc_preg (cfg);
4532         NEW_BBLOCK (cfg, end_bb);
4533 #endif
4534
4535         NEW_BBLOCK (cfg, ok_result_bb);
4536
4537         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4538         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4539
4540         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4541
4542         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4543 #ifndef DISABLE_REMOTING
4544                 NEW_BBLOCK (cfg, interface_fail_bb);
4545         
4546                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4547                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4548                 MONO_START_BB (cfg, interface_fail_bb);
4549                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4550
4551                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4552
4553                 tmp_reg = alloc_preg (cfg);             
4554                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4555                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4556                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4557                 
4558                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4559                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4560 #else
4561                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4562                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4563                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4564 #endif
4565         } else {
4566 #ifndef DISABLE_REMOTING
4567                 NEW_BBLOCK (cfg, no_proxy_bb);
4568
4569                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4570                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4571                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4572
4573                 tmp_reg = alloc_preg (cfg);
4574                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4575                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4576
4577                 tmp_reg = alloc_preg (cfg);
4578                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4579                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4580                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4581
4582                 NEW_BBLOCK (cfg, fail_1_bb);
4583                 
4584                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4585
4586                 MONO_START_BB (cfg, fail_1_bb);
4587
4588                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4589                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4590
4591                 MONO_START_BB (cfg, no_proxy_bb);
4592
4593                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4594 #else
4595                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4596 #endif
4597         }
4598
4599         MONO_START_BB (cfg, ok_result_bb);
4600
4601         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4602
4603 #ifndef DISABLE_REMOTING
4604         MONO_START_BB (cfg, end_bb);
4605 #endif
4606
4607         /* FIXME: */
4608         MONO_INST_NEW (cfg, ins, OP_ICONST);
4609         ins->dreg = dreg;
4610         ins->type = STACK_I4;
4611
4612         return ins;
4613 }
4614
4615 static G_GNUC_UNUSED MonoInst*
4616 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4617 {
4618         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4619         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4620         gboolean is_i4 = TRUE;
4621
4622         switch (enum_type->type) {
4623         case MONO_TYPE_I8:
4624         case MONO_TYPE_U8:
4625 #if SIZEOF_REGISTER == 8
4626         case MONO_TYPE_I:
4627         case MONO_TYPE_U:
4628 #endif
4629                 is_i4 = FALSE;
4630                 break;
4631         }
4632
4633         {
4634                 MonoInst *load, *and, *cmp, *ceq;
4635                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4636                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4637                 int dest_reg = alloc_ireg (cfg);
4638
4639                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4640                 EMIT_NEW_BIALU (cfg, and, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4641                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4642                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4643
4644                 ceq->type = STACK_I4;
4645
4646                 if (!is_i4) {
4647                         load = mono_decompose_opcode (cfg, load);
4648                         and = mono_decompose_opcode (cfg, and);
4649                         cmp = mono_decompose_opcode (cfg, cmp);
4650                         ceq = mono_decompose_opcode (cfg, ceq);
4651                 }
4652
4653                 return ceq;
4654         }
4655 }
4656
4657 /*
4658  * Returns NULL and set the cfg exception on error.
4659  */
4660 static G_GNUC_UNUSED MonoInst*
4661 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual)
4662 {
4663         MonoInst *ptr;
4664         int dreg;
4665         gpointer trampoline;
4666         MonoInst *obj, *method_ins, *tramp_ins;
4667         MonoDomain *domain;
4668         guint8 **code_slot;
4669         
4670         // FIXME reenable optimisation for virtual case
4671         if (virtual)
4672                 return NULL;
4673
4674         if (virtual) {
4675                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4676                 g_assert (invoke);
4677
4678                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4679                         return NULL;
4680         }
4681
4682         obj = handle_alloc (cfg, klass, FALSE, 0);
4683         if (!obj)
4684                 return NULL;
4685
4686         /* Inline the contents of mono_delegate_ctor */
4687
4688         /* Set target field */
4689         /* Optimize away setting of NULL target */
4690         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4691                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4692                 if (cfg->gen_write_barriers) {
4693                         dreg = alloc_preg (cfg);
4694                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
4695                         emit_write_barrier (cfg, ptr, target);
4696                 }
4697         }
4698
4699         /* Set method field */
4700         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4701         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4702
4703         /* 
4704          * To avoid looking up the compiled code belonging to the target method
4705          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4706          * store it, and we fill it after the method has been compiled.
4707          */
4708         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4709                 MonoInst *code_slot_ins;
4710
4711                 if (context_used) {
4712                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4713                 } else {
4714                         domain = mono_domain_get ();
4715                         mono_domain_lock (domain);
4716                         if (!domain_jit_info (domain)->method_code_hash)
4717                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4718                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4719                         if (!code_slot) {
4720                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4721                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4722                         }
4723                         mono_domain_unlock (domain);
4724
4725                         if (cfg->compile_aot)
4726                                 EMIT_NEW_AOTCONST (cfg, code_slot_ins, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
4727                         else
4728                                 EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4729                 }
4730                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
4731         }
4732
4733         if (cfg->compile_aot) {
4734                 MonoDelegateClassMethodPair *del_tramp;
4735
4736                 del_tramp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
4737                 del_tramp->klass = klass;
4738                 del_tramp->method = context_used ? NULL : method;
4739                 del_tramp->virtual = virtual;
4740                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
4741         } else {
4742                 if (virtual)
4743                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
4744                 else
4745                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
4746                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4747         }
4748
4749         /* Set invoke_impl field */
4750         if (virtual) {
4751                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4752         } else {
4753                 dreg = alloc_preg (cfg);
4754                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
4755                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
4756
4757                 dreg = alloc_preg (cfg);
4758                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
4759                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
4760         }
4761
4762         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4763
4764         return obj;
4765 }
4766
4767 static MonoInst*
4768 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4769 {
4770         MonoJitICallInfo *info;
4771
4772         /* Need to register the icall so it gets an icall wrapper */
4773         info = mono_get_array_new_va_icall (rank);
4774
4775         cfg->flags |= MONO_CFG_HAS_VARARGS;
4776
4777         /* mono_array_new_va () needs a vararg calling convention */
4778         cfg->disable_llvm = TRUE;
4779
4780         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4781         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4782 }
4783
4784 static void
4785 mono_emit_load_got_addr (MonoCompile *cfg)
4786 {
4787         MonoInst *getaddr, *dummy_use;
4788
4789         if (!cfg->got_var || cfg->got_var_allocated)
4790                 return;
4791
4792         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4793         getaddr->cil_code = cfg->header->code;
4794         getaddr->dreg = cfg->got_var->dreg;
4795
4796         /* Add it to the start of the first bblock */
4797         if (cfg->bb_entry->code) {
4798                 getaddr->next = cfg->bb_entry->code;
4799                 cfg->bb_entry->code = getaddr;
4800         }
4801         else
4802                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4803
4804         cfg->got_var_allocated = TRUE;
4805
4806         /* 
4807          * Add a dummy use to keep the got_var alive, since real uses might
4808          * only be generated by the back ends.
4809          * Add it to end_bblock, so the variable's lifetime covers the whole
4810          * method.
4811          * It would be better to make the usage of the got var explicit in all
4812          * cases when the backend needs it (i.e. calls, throw etc.), so this
4813          * wouldn't be needed.
4814          */
4815         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4816         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4817 }
4818
4819 static int inline_limit;
4820 static gboolean inline_limit_inited;
4821
4822 static gboolean
4823 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4824 {
4825         MonoMethodHeaderSummary header;
4826         MonoVTable *vtable;
4827 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4828         MonoMethodSignature *sig = mono_method_signature (method);
4829         int i;
4830 #endif
4831
4832         if (cfg->disable_inline)
4833                 return FALSE;
4834         if (cfg->generic_sharing_context)
4835                 return FALSE;
4836
4837         if (cfg->inline_depth > 10)
4838                 return FALSE;
4839
4840 #ifdef MONO_ARCH_HAVE_LMF_OPS
4841         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4842                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4843             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4844                 return TRUE;
4845 #endif
4846
4847
4848         if (!mono_method_get_header_summary (method, &header))
4849                 return FALSE;
4850
4851         /*runtime, icall and pinvoke are checked by summary call*/
4852         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4853             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4854             (mono_class_is_marshalbyref (method->klass)) ||
4855             header.has_clauses)
4856                 return FALSE;
4857
4858         /* also consider num_locals? */
4859         /* Do the size check early to avoid creating vtables */
4860         if (!inline_limit_inited) {
4861                 if (g_getenv ("MONO_INLINELIMIT"))
4862                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4863                 else
4864                         inline_limit = INLINE_LENGTH_LIMIT;
4865                 inline_limit_inited = TRUE;
4866         }
4867         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4868                 return FALSE;
4869
4870         /*
4871          * if we can initialize the class of the method right away, we do,
4872          * otherwise we don't allow inlining if the class needs initialization,
4873          * since it would mean inserting a call to mono_runtime_class_init()
4874          * inside the inlined code
4875          */
4876         if (!(cfg->opt & MONO_OPT_SHARED)) {
4877                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
4878                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
4879                         vtable = mono_class_vtable (cfg->domain, method->klass);
4880                         if (!vtable)
4881                                 return FALSE;
4882                         if (!cfg->compile_aot)
4883                                 mono_runtime_class_init (vtable);
4884                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4885                         if (cfg->run_cctors && method->klass->has_cctor) {
4886                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4887                                 if (!method->klass->runtime_info)
4888                                         /* No vtable created yet */
4889                                         return FALSE;
4890                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4891                                 if (!vtable)
4892                                         return FALSE;
4893                                 /* This makes so that inline cannot trigger */
4894                                 /* .cctors: too many apps depend on them */
4895                                 /* running with a specific order... */
4896                                 if (! vtable->initialized)
4897                                         return FALSE;
4898                                 mono_runtime_class_init (vtable);
4899                         }
4900                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4901                         if (!method->klass->runtime_info)
4902                                 /* No vtable created yet */
4903                                 return FALSE;
4904                         vtable = mono_class_vtable (cfg->domain, method->klass);
4905                         if (!vtable)
4906                                 return FALSE;
4907                         if (!vtable->initialized)
4908                                 return FALSE;
4909                 }
4910         } else {
4911                 /* 
4912                  * If we're compiling for shared code
4913                  * the cctor will need to be run at aot method load time, for example,
4914                  * or at the end of the compilation of the inlining method.
4915                  */
4916                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4917                         return FALSE;
4918         }
4919
4920         /*
4921          * CAS - do not inline methods with declarative security
4922          * Note: this has to be before any possible return TRUE;
4923          */
4924         if (mono_security_method_has_declsec (method))
4925                 return FALSE;
4926
4927 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4928         if (mono_arch_is_soft_float ()) {
4929                 /* FIXME: */
4930                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4931                         return FALSE;
4932                 for (i = 0; i < sig->param_count; ++i)
4933                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4934                                 return FALSE;
4935         }
4936 #endif
4937
4938         if (g_list_find (cfg->dont_inline, method))
4939                 return FALSE;
4940
4941         return TRUE;
4942 }
4943
4944 static gboolean
4945 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4946 {
4947         if (!cfg->compile_aot) {
4948                 g_assert (vtable);
4949                 if (vtable->initialized)
4950                         return FALSE;
4951         }
4952
4953         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4954                 if (cfg->method == method)
4955                         return FALSE;
4956         }
4957
4958         if (!mono_class_needs_cctor_run (klass, method))
4959                 return FALSE;
4960
4961         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4962                 /* The initialization is already done before the method is called */
4963                 return FALSE;
4964
4965         return TRUE;
4966 }
4967
4968 static MonoInst*
4969 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4970 {
4971         MonoInst *ins;
4972         guint32 size;
4973         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4974         int context_used;
4975
4976         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
4977                 size = -1;
4978         } else {
4979                 mono_class_init (klass);
4980                 size = mono_class_array_element_size (klass);
4981         }
4982
4983         mult_reg = alloc_preg (cfg);
4984         array_reg = arr->dreg;
4985         index_reg = index->dreg;
4986
4987 #if SIZEOF_REGISTER == 8
4988         /* The array reg is 64 bits but the index reg is only 32 */
4989         if (COMPILE_LLVM (cfg)) {
4990                 /* Not needed */
4991                 index2_reg = index_reg;
4992         } else {
4993                 index2_reg = alloc_preg (cfg);
4994                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4995         }
4996 #else
4997         if (index->type == STACK_I8) {
4998                 index2_reg = alloc_preg (cfg);
4999                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5000         } else {
5001                 index2_reg = index_reg;
5002         }
5003 #endif
5004
5005         if (bcheck)
5006                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5007
5008 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5009         if (size == 1 || size == 2 || size == 4 || size == 8) {
5010                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5011
5012                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5013                 ins->klass = mono_class_get_element_class (klass);
5014                 ins->type = STACK_MP;
5015
5016                 return ins;
5017         }
5018 #endif          
5019
5020         add_reg = alloc_ireg_mp (cfg);
5021
5022         if (size == -1) {
5023                 MonoInst *rgctx_ins;
5024
5025                 /* gsharedvt */
5026                 g_assert (cfg->generic_sharing_context);
5027                 context_used = mini_class_check_context_used (cfg, klass);
5028                 g_assert (context_used);
5029                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5030                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5031         } else {
5032                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5033         }
5034         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5035         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5036         ins->klass = mono_class_get_element_class (klass);
5037         ins->type = STACK_MP;
5038         MONO_ADD_INS (cfg->cbb, ins);
5039
5040         return ins;
5041 }
5042
5043 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5044 static MonoInst*
5045 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5046 {
5047         int bounds_reg = alloc_preg (cfg);
5048         int add_reg = alloc_ireg_mp (cfg);
5049         int mult_reg = alloc_preg (cfg);
5050         int mult2_reg = alloc_preg (cfg);
5051         int low1_reg = alloc_preg (cfg);
5052         int low2_reg = alloc_preg (cfg);
5053         int high1_reg = alloc_preg (cfg);
5054         int high2_reg = alloc_preg (cfg);
5055         int realidx1_reg = alloc_preg (cfg);
5056         int realidx2_reg = alloc_preg (cfg);
5057         int sum_reg = alloc_preg (cfg);
5058         int index1, index2, tmpreg;
5059         MonoInst *ins;
5060         guint32 size;
5061
5062         mono_class_init (klass);
5063         size = mono_class_array_element_size (klass);
5064
5065         index1 = index_ins1->dreg;
5066         index2 = index_ins2->dreg;
5067
5068 #if SIZEOF_REGISTER == 8
5069         /* The array reg is 64 bits but the index reg is only 32 */
5070         if (COMPILE_LLVM (cfg)) {
5071                 /* Not needed */
5072         } else {
5073                 tmpreg = alloc_preg (cfg);
5074                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5075                 index1 = tmpreg;
5076                 tmpreg = alloc_preg (cfg);
5077                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5078                 index2 = tmpreg;
5079         }
5080 #else
5081         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5082         tmpreg = -1;
5083 #endif
5084
5085         /* range checking */
5086         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5087                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5088
5089         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5090                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5091         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5092         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5093                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5094         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5095         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5096
5097         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5098                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5099         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5100         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5101                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5102         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5103         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5104
5105         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5106         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5107         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5108         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5109         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5110
5111         ins->type = STACK_MP;
5112         ins->klass = klass;
5113         MONO_ADD_INS (cfg->cbb, ins);
5114
5115         return ins;
5116 }
5117 #endif
5118
5119 static MonoInst*
5120 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5121 {
5122         int rank;
5123         MonoInst *addr;
5124         MonoMethod *addr_method;
5125         int element_size;
5126
5127         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5128
5129         if (rank == 1)
5130                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
5131
5132 #ifndef MONO_ARCH_EMULATE_MUL_DIV
5133         /* emit_ldelema_2 depends on OP_LMUL */
5134         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
5135                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
5136         }
5137 #endif
5138
5139         element_size = mono_class_array_element_size (cmethod->klass->element_class);
5140         addr_method = mono_marshal_get_array_address (rank, element_size);
5141         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5142
5143         return addr;
5144 }
5145
5146 static MonoBreakPolicy
5147 always_insert_breakpoint (MonoMethod *method)
5148 {
5149         return MONO_BREAK_POLICY_ALWAYS;
5150 }
5151
5152 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5153
5154 /**
5155  * mono_set_break_policy:
5156  * policy_callback: the new callback function
5157  *
5158  * Allow embedders to decide wherther to actually obey breakpoint instructions
5159  * (both break IL instructions and Debugger.Break () method calls), for example
5160  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5161  * untrusted or semi-trusted code.
5162  *
5163  * @policy_callback will be called every time a break point instruction needs to
5164  * be inserted with the method argument being the method that calls Debugger.Break()
5165  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5166  * if it wants the breakpoint to not be effective in the given method.
5167  * #MONO_BREAK_POLICY_ALWAYS is the default.
5168  */
5169 void
5170 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5171 {
5172         if (policy_callback)
5173                 break_policy_func = policy_callback;
5174         else
5175                 break_policy_func = always_insert_breakpoint;
5176 }
5177
5178 static gboolean
5179 should_insert_brekpoint (MonoMethod *method) {
5180         switch (break_policy_func (method)) {
5181         case MONO_BREAK_POLICY_ALWAYS:
5182                 return TRUE;
5183         case MONO_BREAK_POLICY_NEVER:
5184                 return FALSE;
5185         case MONO_BREAK_POLICY_ON_DBG:
5186                 g_warning ("mdb no longer supported");
5187                 return FALSE;
5188         default:
5189                 g_warning ("Incorrect value returned from break policy callback");
5190                 return FALSE;
5191         }
5192 }
5193
5194 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5195 static MonoInst*
5196 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5197 {
5198         MonoInst *addr, *store, *load;
5199         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5200
5201         /* the bounds check is already done by the callers */
5202         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5203         if (is_set) {
5204                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5205                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5206                 if (mini_type_is_reference (cfg, fsig->params [2]))
5207                         emit_write_barrier (cfg, addr, load);
5208         } else {
5209                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5210                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5211         }
5212         return store;
5213 }
5214
5215
5216 static gboolean
5217 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5218 {
5219         return mini_type_is_reference (cfg, &klass->byval_arg);
5220 }
5221
5222 static MonoInst*
5223 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5224 {
5225         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5226                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5227                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5228                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5229                 MonoInst *iargs [3];
5230
5231                 if (!helper->slot)
5232                         mono_class_setup_vtable (obj_array);
5233                 g_assert (helper->slot);
5234
5235                 if (sp [0]->type != STACK_OBJ)
5236                         return NULL;
5237                 if (sp [2]->type != STACK_OBJ)
5238                         return NULL;
5239
5240                 iargs [2] = sp [2];
5241                 iargs [1] = sp [1];
5242                 iargs [0] = sp [0];
5243
5244                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5245         } else {
5246                 MonoInst *ins;
5247
5248                 if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
5249                         MonoInst *addr;
5250
5251                         // FIXME-VT: OP_ICONST optimization
5252                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5253                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5254                         ins->opcode = OP_STOREV_MEMBASE;
5255                 } else if (sp [1]->opcode == OP_ICONST) {
5256                         int array_reg = sp [0]->dreg;
5257                         int index_reg = sp [1]->dreg;
5258                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5259
5260                         if (safety_checks)
5261                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5262                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5263                 } else {
5264                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5265                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5266                         if (generic_class_is_reference_type (cfg, klass))
5267                                 emit_write_barrier (cfg, addr, sp [2]);
5268                 }
5269                 return ins;
5270         }
5271 }
5272
5273 static MonoInst*
5274 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5275 {
5276         MonoClass *eklass;
5277         
5278         if (is_set)
5279                 eklass = mono_class_from_mono_type (fsig->params [2]);
5280         else
5281                 eklass = mono_class_from_mono_type (fsig->ret);
5282
5283         if (is_set) {
5284                 return emit_array_store (cfg, eklass, args, FALSE);
5285         } else {
5286                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5287                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5288                 return ins;
5289         }
5290 }
5291
5292 static gboolean
5293 is_unsafe_mov_compatible (MonoClass *param_klass, MonoClass *return_klass)
5294 {
5295         uint32_t align;
5296
5297         //Only allow for valuetypes
5298         if (!param_klass->valuetype || !return_klass->valuetype)
5299                 return FALSE;
5300
5301         //That are blitable
5302         if (param_klass->has_references || return_klass->has_references)
5303                 return FALSE;
5304
5305         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5306         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5307                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)))
5308                 return FALSE;
5309
5310         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5311                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8)
5312                 return FALSE;
5313
5314         //And have the same size
5315         if (mono_class_value_size (param_klass, &align) != mono_class_value_size (return_klass, &align))
5316                 return FALSE;
5317         return TRUE;
5318 }
5319
5320 static MonoInst*
5321 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5322 {
5323         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5324         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5325
5326         //Valuetypes that are semantically equivalent
5327         if (is_unsafe_mov_compatible (param_klass, return_klass))
5328                 return args [0];
5329
5330         //Arrays of valuetypes that are semantically equivalent
5331         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (param_klass->element_class, return_klass->element_class))
5332                 return args [0];
5333
5334         return NULL;
5335 }
5336
5337 static MonoInst*
5338 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5339 {
5340 #ifdef MONO_ARCH_SIMD_INTRINSICS
5341         MonoInst *ins = NULL;
5342
5343         if (cfg->opt & MONO_OPT_SIMD) {
5344                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5345                 if (ins)
5346                         return ins;
5347         }
5348 #endif
5349
5350         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5351 }
5352
5353 static MonoInst*
5354 emit_memory_barrier (MonoCompile *cfg, int kind)
5355 {
5356         MonoInst *ins = NULL;
5357         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5358         MONO_ADD_INS (cfg->cbb, ins);
5359         ins->backend.memory_barrier_kind = kind;
5360
5361         return ins;
5362 }
5363
5364 static MonoInst*
5365 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5366 {
5367         MonoInst *ins = NULL;
5368         int opcode = 0;
5369
5370         /* The LLVM backend supports these intrinsics */
5371         if (cmethod->klass == mono_defaults.math_class) {
5372                 if (strcmp (cmethod->name, "Sin") == 0) {
5373                         opcode = OP_SIN;
5374                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5375                         opcode = OP_COS;
5376                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5377                         opcode = OP_SQRT;
5378                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5379                         opcode = OP_ABS;
5380                 }
5381
5382                 if (opcode && fsig->param_count == 1) {
5383                         MONO_INST_NEW (cfg, ins, opcode);
5384                         ins->type = STACK_R8;
5385                         ins->dreg = mono_alloc_freg (cfg);
5386                         ins->sreg1 = args [0]->dreg;
5387                         MONO_ADD_INS (cfg->cbb, ins);
5388                 }
5389
5390                 opcode = 0;
5391                 if (cfg->opt & MONO_OPT_CMOV) {
5392                         if (strcmp (cmethod->name, "Min") == 0) {
5393                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5394                                         opcode = OP_IMIN;
5395                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5396                                         opcode = OP_IMIN_UN;
5397                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5398                                         opcode = OP_LMIN;
5399                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5400                                         opcode = OP_LMIN_UN;
5401                         } else if (strcmp (cmethod->name, "Max") == 0) {
5402                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5403                                         opcode = OP_IMAX;
5404                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5405                                         opcode = OP_IMAX_UN;
5406                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5407                                         opcode = OP_LMAX;
5408                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5409                                         opcode = OP_LMAX_UN;
5410                         }
5411                 }
5412
5413                 if (opcode && fsig->param_count == 2) {
5414                         MONO_INST_NEW (cfg, ins, opcode);
5415                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5416                         ins->dreg = mono_alloc_ireg (cfg);
5417                         ins->sreg1 = args [0]->dreg;
5418                         ins->sreg2 = args [1]->dreg;
5419                         MONO_ADD_INS (cfg->cbb, ins);
5420                 }
5421         }
5422
5423         return ins;
5424 }
5425
5426 static MonoInst*
5427 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5428 {
5429         if (cmethod->klass == mono_defaults.array_class) {
5430                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5431                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5432                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5433                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5434                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5435                         return emit_array_unsafe_mov (cfg, fsig, args);
5436         }
5437
5438         return NULL;
5439 }
5440
5441 static MonoInst*
5442 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5443 {
5444         MonoInst *ins = NULL;
5445         
5446         static MonoClass *runtime_helpers_class = NULL;
5447         if (! runtime_helpers_class)
5448                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5449                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5450
5451         if (cmethod->klass == mono_defaults.string_class) {
5452                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count == 2) {
5453                         int dreg = alloc_ireg (cfg);
5454                         int index_reg = alloc_preg (cfg);
5455                         int mult_reg = alloc_preg (cfg);
5456                         int add_reg = alloc_preg (cfg);
5457
5458 #if SIZEOF_REGISTER == 8
5459                         /* The array reg is 64 bits but the index reg is only 32 */
5460                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5461 #else
5462                         index_reg = args [1]->dreg;
5463 #endif  
5464                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5465
5466 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5467                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5468                         add_reg = ins->dreg;
5469                         /* Avoid a warning */
5470                         mult_reg = 0;
5471                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5472                                                                    add_reg, 0);
5473 #else
5474                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5475                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5476                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5477                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5478 #endif
5479                         type_from_op (ins, NULL, NULL);
5480                         return ins;
5481                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5482                         int dreg = alloc_ireg (cfg);
5483                         /* Decompose later to allow more optimizations */
5484                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5485                         ins->type = STACK_I4;
5486                         ins->flags |= MONO_INST_FAULT;
5487                         cfg->cbb->has_array_access = TRUE;
5488                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5489
5490                         return ins;
5491                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0 && fsig->param_count == 3) {
5492                         int mult_reg = alloc_preg (cfg);
5493                         int add_reg = alloc_preg (cfg);
5494
5495                         /* The corlib functions check for oob already. */
5496                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5497                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5498                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, MONO_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5499                         return cfg->cbb->last_ins;
5500                 } else 
5501                         return NULL;
5502         } else if (cmethod->klass == mono_defaults.object_class) {
5503
5504                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count == 1) {
5505                         int dreg = alloc_ireg_ref (cfg);
5506                         int vt_reg = alloc_preg (cfg);
5507                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5508                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5509                         type_from_op (ins, NULL, NULL);
5510
5511                         return ins;
5512 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5513                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5514                         int dreg = alloc_ireg (cfg);
5515                         int t1 = alloc_ireg (cfg);
5516         
5517                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5518                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5519                         ins->type = STACK_I4;
5520
5521                         return ins;
5522 #endif
5523                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5524                         MONO_INST_NEW (cfg, ins, OP_NOP);
5525                         MONO_ADD_INS (cfg->cbb, ins);
5526                         return ins;
5527                 } else
5528                         return NULL;
5529         } else if (cmethod->klass == mono_defaults.array_class) {
5530                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5531                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5532                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count == 3 && !cfg->gsharedvt)
5533                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5534
5535 #ifndef MONO_BIG_ARRAYS
5536                 /*
5537                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5538                  * Array methods.
5539                  */
5540                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count == 2) ||
5541                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count == 2)) &&
5542                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5543                         int dreg = alloc_ireg (cfg);
5544                         int bounds_reg = alloc_ireg_mp (cfg);
5545                         MonoBasicBlock *end_bb, *szarray_bb;
5546                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5547
5548                         NEW_BBLOCK (cfg, end_bb);
5549                         NEW_BBLOCK (cfg, szarray_bb);
5550
5551                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5552                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5553                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5554                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5555                         /* Non-szarray case */
5556                         if (get_length)
5557                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5558                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5559                         else
5560                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5561                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5562                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5563                         MONO_START_BB (cfg, szarray_bb);
5564                         /* Szarray case */
5565                         if (get_length)
5566                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5567                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5568                         else
5569                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5570                         MONO_START_BB (cfg, end_bb);
5571
5572                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5573                         ins->type = STACK_I4;
5574                         
5575                         return ins;
5576                 }
5577 #endif
5578
5579                 if (cmethod->name [0] != 'g')
5580                         return NULL;
5581
5582                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count == 1) {
5583                         int dreg = alloc_ireg (cfg);
5584                         int vtable_reg = alloc_preg (cfg);
5585                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5586                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5587                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5588                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
5589                         type_from_op (ins, NULL, NULL);
5590
5591                         return ins;
5592                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count == 1) {
5593                         int dreg = alloc_ireg (cfg);
5594
5595                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5596                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
5597                         type_from_op (ins, NULL, NULL);
5598
5599                         return ins;
5600                 } else
5601                         return NULL;
5602         } else if (cmethod->klass == runtime_helpers_class) {
5603
5604                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
5605                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
5606                         return ins;
5607                 } else
5608                         return NULL;
5609         } else if (cmethod->klass == mono_defaults.thread_class) {
5610                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
5611                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5612                         MONO_ADD_INS (cfg->cbb, ins);
5613                         return ins;
5614                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
5615                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5616                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
5617                         guint32 opcode = 0;
5618                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5619
5620                         if (fsig->params [0]->type == MONO_TYPE_I1)
5621                                 opcode = OP_LOADI1_MEMBASE;
5622                         else if (fsig->params [0]->type == MONO_TYPE_U1)
5623                                 opcode = OP_LOADU1_MEMBASE;
5624                         else if (fsig->params [0]->type == MONO_TYPE_I2)
5625                                 opcode = OP_LOADI2_MEMBASE;
5626                         else if (fsig->params [0]->type == MONO_TYPE_U2)
5627                                 opcode = OP_LOADU2_MEMBASE;
5628                         else if (fsig->params [0]->type == MONO_TYPE_I4)
5629                                 opcode = OP_LOADI4_MEMBASE;
5630                         else if (fsig->params [0]->type == MONO_TYPE_U4)
5631                                 opcode = OP_LOADU4_MEMBASE;
5632                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5633                                 opcode = OP_LOADI8_MEMBASE;
5634                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5635                                 opcode = OP_LOADR4_MEMBASE;
5636                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5637                                 opcode = OP_LOADR8_MEMBASE;
5638                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5639                                 opcode = OP_LOAD_MEMBASE;
5640
5641                         if (opcode) {
5642                                 MONO_INST_NEW (cfg, ins, opcode);
5643                                 ins->inst_basereg = args [0]->dreg;
5644                                 ins->inst_offset = 0;
5645                                 MONO_ADD_INS (cfg->cbb, ins);
5646
5647                                 switch (fsig->params [0]->type) {
5648                                 case MONO_TYPE_I1:
5649                                 case MONO_TYPE_U1:
5650                                 case MONO_TYPE_I2:
5651                                 case MONO_TYPE_U2:
5652                                 case MONO_TYPE_I4:
5653                                 case MONO_TYPE_U4:
5654                                         ins->dreg = mono_alloc_ireg (cfg);
5655                                         break;
5656                                 case MONO_TYPE_I8:
5657                                 case MONO_TYPE_U8:
5658                                         ins->dreg = mono_alloc_lreg (cfg);
5659                                         break;
5660                                 case MONO_TYPE_I:
5661                                 case MONO_TYPE_U:
5662                                         ins->dreg = mono_alloc_ireg (cfg);
5663                                         break;
5664                                 case MONO_TYPE_R4:
5665                                 case MONO_TYPE_R8:
5666                                         ins->dreg = mono_alloc_freg (cfg);
5667                                         break;
5668                                 default:
5669                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5670                                         ins->dreg = mono_alloc_ireg_ref (cfg);
5671                                         break;
5672                                 }
5673
5674                                 if (opcode == OP_LOADI8_MEMBASE)
5675                                         ins = mono_decompose_opcode (cfg, ins);
5676
5677                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
5678
5679                                 return ins;
5680                         }
5681                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
5682                         guint32 opcode = 0;
5683                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5684
5685                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
5686                                 opcode = OP_STOREI1_MEMBASE_REG;
5687                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
5688                                 opcode = OP_STOREI2_MEMBASE_REG;
5689                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
5690                                 opcode = OP_STOREI4_MEMBASE_REG;
5691                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
5692                                 opcode = OP_STOREI8_MEMBASE_REG;
5693                         else if (fsig->params [0]->type == MONO_TYPE_R4)
5694                                 opcode = OP_STORER4_MEMBASE_REG;
5695                         else if (fsig->params [0]->type == MONO_TYPE_R8)
5696                                 opcode = OP_STORER8_MEMBASE_REG;
5697                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
5698                                 opcode = OP_STORE_MEMBASE_REG;
5699
5700                         if (opcode) {
5701                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
5702
5703                                 MONO_INST_NEW (cfg, ins, opcode);
5704                                 ins->sreg1 = args [1]->dreg;
5705                                 ins->inst_destbasereg = args [0]->dreg;
5706                                 ins->inst_offset = 0;
5707                                 MONO_ADD_INS (cfg->cbb, ins);
5708
5709                                 if (opcode == OP_STOREI8_MEMBASE_REG)
5710                                         ins = mono_decompose_opcode (cfg, ins);
5711
5712                                 return ins;
5713                         }
5714                 }
5715         } else if (cmethod->klass == mono_defaults.monitor_class) {
5716 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5717                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5718                         MonoCallInst *call;
5719
5720                         if (COMPILE_LLVM (cfg)) {
5721                                 /* 
5722                                  * Pass the argument normally, the LLVM backend will handle the
5723                                  * calling convention problems.
5724                                  */
5725                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5726                         } else {
5727                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5728                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5729                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5730                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5731                         }
5732
5733                         return (MonoInst*)call;
5734 #if defined(MONO_ARCH_MONITOR_LOCK_TAKEN_REG)
5735                 } else if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5736                         MonoCallInst *call;
5737
5738                         if (COMPILE_LLVM (cfg)) {
5739                                 /*
5740                                  * Pass the argument normally, the LLVM backend will handle the
5741                                  * calling convention problems.
5742                                  */
5743                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4, NULL, helper_sig_monitor_enter_v4_trampoline_llvm, args);
5744                         } else {
5745                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER_V4,
5746                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5747                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg, MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5748                                 mono_call_inst_add_outarg_reg (cfg, call, args [1]->dreg, MONO_ARCH_MONITOR_LOCK_TAKEN_REG, FALSE);
5749                         }
5750
5751                         return (MonoInst*)call;
5752 #endif
5753                 } else if (strcmp (cmethod->name, "Exit") == 0 && fsig->param_count == 1) {
5754                         MonoCallInst *call;
5755
5756                         if (COMPILE_LLVM (cfg)) {
5757                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5758                         } else {
5759                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5760                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5761                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5762                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5763                         }
5764
5765                         return (MonoInst*)call;
5766                 }
5767 #endif
5768         } else if (cmethod->klass->image == mono_defaults.corlib &&
5769                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5770                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5771                 ins = NULL;
5772
5773 #if SIZEOF_REGISTER == 8
5774                 if (strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5775                         if (mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
5776                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
5777                                 ins->dreg = mono_alloc_preg (cfg);
5778                                 ins->sreg1 = args [0]->dreg;
5779                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
5780                                 MONO_ADD_INS (cfg->cbb, ins);
5781                         } else {
5782                                 MonoInst *load_ins;
5783
5784                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5785
5786                                 /* 64 bit reads are already atomic */
5787                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
5788                                 load_ins->dreg = mono_alloc_preg (cfg);
5789                                 load_ins->inst_basereg = args [0]->dreg;
5790                                 load_ins->inst_offset = 0;
5791                                 MONO_ADD_INS (cfg->cbb, load_ins);
5792
5793                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
5794
5795                                 ins = load_ins;
5796                         }
5797                 }
5798 #endif
5799
5800                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
5801                         MonoInst *ins_iconst;
5802                         guint32 opcode = 0;
5803
5804                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5805                                 opcode = OP_ATOMIC_ADD_I4;
5806                                 cfg->has_atomic_add_i4 = TRUE;
5807                         }
5808 #if SIZEOF_REGISTER == 8
5809                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5810                                 opcode = OP_ATOMIC_ADD_I8;
5811 #endif
5812                         if (opcode) {
5813                                 if (!mono_arch_opcode_supported (opcode))
5814                                         return NULL;
5815                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5816                                 ins_iconst->inst_c0 = 1;
5817                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5818                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5819
5820                                 MONO_INST_NEW (cfg, ins, opcode);
5821                                 ins->dreg = mono_alloc_ireg (cfg);
5822                                 ins->inst_basereg = args [0]->dreg;
5823                                 ins->inst_offset = 0;
5824                                 ins->sreg2 = ins_iconst->dreg;
5825                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5826                                 MONO_ADD_INS (cfg->cbb, ins);
5827                         }
5828                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
5829                         MonoInst *ins_iconst;
5830                         guint32 opcode = 0;
5831
5832                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5833                                 opcode = OP_ATOMIC_ADD_I4;
5834                                 cfg->has_atomic_add_i4 = TRUE;
5835                         }
5836 #if SIZEOF_REGISTER == 8
5837                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5838                                 opcode = OP_ATOMIC_ADD_I8;
5839 #endif
5840                         if (opcode) {
5841                                 if (!mono_arch_opcode_supported (opcode))
5842                                         return NULL;
5843                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5844                                 ins_iconst->inst_c0 = -1;
5845                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5846                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5847
5848                                 MONO_INST_NEW (cfg, ins, opcode);
5849                                 ins->dreg = mono_alloc_ireg (cfg);
5850                                 ins->inst_basereg = args [0]->dreg;
5851                                 ins->inst_offset = 0;
5852                                 ins->sreg2 = ins_iconst->dreg;
5853                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5854                                 MONO_ADD_INS (cfg->cbb, ins);
5855                         }
5856                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
5857                         guint32 opcode = 0;
5858
5859                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5860                                 opcode = OP_ATOMIC_ADD_I4;
5861                                 cfg->has_atomic_add_i4 = TRUE;
5862                         }
5863 #if SIZEOF_REGISTER == 8
5864                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5865                                 opcode = OP_ATOMIC_ADD_I8;
5866 #endif
5867                         if (opcode) {
5868                                 if (!mono_arch_opcode_supported (opcode))
5869                                         return NULL;
5870                                 MONO_INST_NEW (cfg, ins, opcode);
5871                                 ins->dreg = mono_alloc_ireg (cfg);
5872                                 ins->inst_basereg = args [0]->dreg;
5873                                 ins->inst_offset = 0;
5874                                 ins->sreg2 = args [1]->dreg;
5875                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
5876                                 MONO_ADD_INS (cfg->cbb, ins);
5877                         }
5878                 }
5879                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
5880                         guint32 opcode;
5881                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
5882
5883                         if (fsig->params [0]->type == MONO_TYPE_I4) {
5884                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5885                                 cfg->has_atomic_exchange_i4 = TRUE;
5886                         }
5887 #if SIZEOF_REGISTER == 8
5888                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5889                                         (fsig->params [0]->type == MONO_TYPE_I))
5890                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5891 #else
5892                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I)) {
5893                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5894                                 cfg->has_atomic_exchange_i4 = TRUE;
5895                         }
5896 #endif
5897                         else
5898                                 return NULL;
5899
5900                         if (!mono_arch_opcode_supported (opcode))
5901                                 return NULL;
5902
5903                         MONO_INST_NEW (cfg, ins, opcode);
5904                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5905                         ins->inst_basereg = args [0]->dreg;
5906                         ins->inst_offset = 0;
5907                         ins->sreg2 = args [1]->dreg;
5908                         MONO_ADD_INS (cfg->cbb, ins);
5909
5910                         switch (fsig->params [0]->type) {
5911                         case MONO_TYPE_I4:
5912                                 ins->type = STACK_I4;
5913                                 break;
5914                         case MONO_TYPE_I8:
5915                                 ins->type = STACK_I8;
5916                                 break;
5917                         case MONO_TYPE_I:
5918 #if SIZEOF_REGISTER == 8
5919                                 ins->type = STACK_I8;
5920 #else
5921                                 ins->type = STACK_I4;
5922 #endif
5923                                 break;
5924                         default:
5925                                 g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5926                                 ins->type = STACK_OBJ;
5927                                 break;
5928                         }
5929
5930                         if (cfg->gen_write_barriers && is_ref)
5931                                 emit_write_barrier (cfg, args [0], args [1]);
5932                 }
5933                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
5934                         int size = 0;
5935                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5936
5937                         if (fsig->params [1]->type == MONO_TYPE_I4)
5938                                 size = 4;
5939                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5940                                 size = sizeof (gpointer);
5941 #if SIZEOF_REGISTER == 8
5942                         else if (fsig->params [1]->type == MONO_TYPE_I8)
5943                                 size = 8;
5944 #endif
5945
5946                         if (size == 4) {
5947                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5948                                         return NULL;
5949                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5950                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5951                                 ins->sreg1 = args [0]->dreg;
5952                                 ins->sreg2 = args [1]->dreg;
5953                                 ins->sreg3 = args [2]->dreg;
5954                                 MONO_ADD_INS (cfg->cbb, ins);
5955                                 cfg->has_atomic_cas_i4 = TRUE;
5956                         } else if (size == 8) {
5957                                 if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I8))
5958                                         return NULL;
5959                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5960                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5961                                 ins->sreg1 = args [0]->dreg;
5962                                 ins->sreg2 = args [1]->dreg;
5963                                 ins->sreg3 = args [2]->dreg;
5964                                 MONO_ADD_INS (cfg->cbb, ins);
5965                         } else {
5966                                 /* g_assert_not_reached (); */
5967                         }
5968
5969                         if (ins) {
5970                                 switch (fsig->params [0]->type) {
5971                                 case MONO_TYPE_I4:
5972                                         ins->type = STACK_I4;
5973                                         break;
5974                                 case MONO_TYPE_I8:
5975                                         ins->type = STACK_I8;
5976                                         break;
5977                                 case MONO_TYPE_I:
5978 #if SIZEOF_REGISTER == 8
5979                                         ins->type = STACK_I8;
5980 #else
5981                                         ins->type = STACK_I4;
5982 #endif
5983                                         break;
5984                                 default:
5985                                         g_assert (mini_type_is_reference (cfg, fsig->params [0]));
5986                                         ins->type = STACK_OBJ;
5987                                         break;
5988                                 }
5989                         }
5990
5991                         if (cfg->gen_write_barriers && is_ref)
5992                                 emit_write_barrier (cfg, args [0], args [1]);
5993                 }
5994                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
5995                          fsig->params [1]->type == MONO_TYPE_I4) {
5996                         MonoInst *cmp, *ceq;
5997
5998                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
5999                                 return NULL;
6000
6001                         /* int32 r = CAS (location, value, comparand); */
6002                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6003                         ins->dreg = alloc_ireg (cfg);
6004                         ins->sreg1 = args [0]->dreg;
6005                         ins->sreg2 = args [1]->dreg;
6006                         ins->sreg3 = args [2]->dreg;
6007                         ins->type = STACK_I4;
6008                         MONO_ADD_INS (cfg->cbb, ins);
6009
6010                         /* bool result = r == comparand; */
6011                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6012                         cmp->sreg1 = ins->dreg;
6013                         cmp->sreg2 = args [2]->dreg;
6014                         cmp->type = STACK_I4;
6015                         MONO_ADD_INS (cfg->cbb, cmp);
6016
6017                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6018                         ceq->dreg = alloc_ireg (cfg);
6019                         ceq->type = STACK_I4;
6020                         MONO_ADD_INS (cfg->cbb, ceq);
6021
6022                         /* *success = result; */
6023                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6024
6025                         cfg->has_atomic_cas_i4 = TRUE;
6026                 }
6027                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6028                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6029
6030                 if (ins)
6031                         return ins;
6032         } else if (cmethod->klass->image == mono_defaults.corlib &&
6033                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6034                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6035                 ins = NULL;
6036
6037                 if (!strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6038                         guint32 opcode = 0;
6039                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6040                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6041
6042                         if (fsig->params [0]->type == MONO_TYPE_I1)
6043                                 opcode = OP_ATOMIC_LOAD_I1;
6044                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6045                                 opcode = OP_ATOMIC_LOAD_U1;
6046                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6047                                 opcode = OP_ATOMIC_LOAD_I2;
6048                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6049                                 opcode = OP_ATOMIC_LOAD_U2;
6050                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6051                                 opcode = OP_ATOMIC_LOAD_I4;
6052                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6053                                 opcode = OP_ATOMIC_LOAD_U4;
6054                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6055                                 opcode = OP_ATOMIC_LOAD_R4;
6056                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6057                                 opcode = OP_ATOMIC_LOAD_R8;
6058 #if SIZEOF_REGISTER == 8
6059                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6060                                 opcode = OP_ATOMIC_LOAD_I8;
6061                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6062                                 opcode = OP_ATOMIC_LOAD_U8;
6063 #else
6064                         else if (fsig->params [0]->type == MONO_TYPE_I)
6065                                 opcode = OP_ATOMIC_LOAD_I4;
6066                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6067                                 opcode = OP_ATOMIC_LOAD_U4;
6068 #endif
6069
6070                         if (opcode) {
6071                                 if (!mono_arch_opcode_supported (opcode))
6072                                         return NULL;
6073
6074                                 MONO_INST_NEW (cfg, ins, opcode);
6075                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6076                                 ins->sreg1 = args [0]->dreg;
6077                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6078                                 MONO_ADD_INS (cfg->cbb, ins);
6079                         }
6080                 }
6081
6082                 if (!strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6083                         guint32 opcode = 0;
6084                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [0]);
6085
6086                         if (fsig->params [0]->type == MONO_TYPE_I1)
6087                                 opcode = OP_ATOMIC_STORE_I1;
6088                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6089                                 opcode = OP_ATOMIC_STORE_U1;
6090                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6091                                 opcode = OP_ATOMIC_STORE_I2;
6092                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6093                                 opcode = OP_ATOMIC_STORE_U2;
6094                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6095                                 opcode = OP_ATOMIC_STORE_I4;
6096                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6097                                 opcode = OP_ATOMIC_STORE_U4;
6098                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6099                                 opcode = OP_ATOMIC_STORE_R4;
6100                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6101                                 opcode = OP_ATOMIC_STORE_R8;
6102 #if SIZEOF_REGISTER == 8
6103                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6104                                 opcode = OP_ATOMIC_STORE_I8;
6105                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6106                                 opcode = OP_ATOMIC_STORE_U8;
6107 #else
6108                         else if (fsig->params [0]->type == MONO_TYPE_I)
6109                                 opcode = OP_ATOMIC_STORE_I4;
6110                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6111                                 opcode = OP_ATOMIC_STORE_U4;
6112 #endif
6113
6114                         if (opcode) {
6115                                 if (!mono_arch_opcode_supported (opcode))
6116                                         return NULL;
6117
6118                                 MONO_INST_NEW (cfg, ins, opcode);
6119                                 ins->dreg = args [0]->dreg;
6120                                 ins->sreg1 = args [1]->dreg;
6121                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6122                                 MONO_ADD_INS (cfg->cbb, ins);
6123
6124                                 if (cfg->gen_write_barriers && is_ref)
6125                                         emit_write_barrier (cfg, args [0], args [1]);
6126                         }
6127                 }
6128
6129                 if (ins)
6130                         return ins;
6131         } else if (cmethod->klass->image == mono_defaults.corlib &&
6132                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6133                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6134                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6135                         if (should_insert_brekpoint (cfg->method)) {
6136                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6137                         } else {
6138                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6139                                 MONO_ADD_INS (cfg->cbb, ins);
6140                         }
6141                         return ins;
6142                 }
6143         } else if (cmethod->klass->image == mono_defaults.corlib &&
6144                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6145                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6146                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6147 #ifdef TARGET_WIN32
6148                         EMIT_NEW_ICONST (cfg, ins, 1);
6149 #else
6150                         EMIT_NEW_ICONST (cfg, ins, 0);
6151 #endif
6152                 }
6153         } else if (cmethod->klass == mono_defaults.math_class) {
6154                 /* 
6155                  * There is general branchless code for Min/Max, but it does not work for 
6156                  * all inputs:
6157                  * http://everything2.com/?node_id=1051618
6158                  */
6159         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6160                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6161                    !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6162                    !strcmp (cmethod->klass->name, "Selector")) {
6163 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
6164                 if (!strcmp (cmethod->klass->name, "GetHandle") && fsig->param_count == 1 &&
6165                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6166                     cfg->compile_aot) {
6167                         MonoInst *pi;
6168                         MonoJumpInfoToken *ji;
6169                         MonoString *s;
6170
6171                         cfg->disable_llvm = TRUE;
6172
6173                         if (args [0]->opcode == OP_GOT_ENTRY) {
6174                                 pi = args [0]->inst_p1;
6175                                 g_assert (pi->opcode == OP_PATCH_INFO);
6176                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6177                                 ji = pi->inst_p0;
6178                         } else {
6179                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6180                                 ji = args [0]->inst_p0;
6181                         }
6182
6183                         NULLIFY_INS (args [0]);
6184
6185                         // FIXME: Ugly
6186                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6187                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6188                         ins->dreg = mono_alloc_ireg (cfg);
6189                         // FIXME: Leaks
6190                         ins->inst_p0 = mono_string_to_utf8 (s);
6191                         MONO_ADD_INS (cfg->cbb, ins);
6192                         return ins;
6193                 }
6194 #endif
6195         }
6196
6197 #ifdef MONO_ARCH_SIMD_INTRINSICS
6198         if (cfg->opt & MONO_OPT_SIMD) {
6199                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6200                 if (ins)
6201                         return ins;
6202         }
6203 #endif
6204
6205         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6206         if (ins)
6207                 return ins;
6208
6209         if (COMPILE_LLVM (cfg)) {
6210                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6211                 if (ins)
6212                         return ins;
6213         }
6214
6215         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6216 }
6217
6218 /*
6219  * This entry point could be used later for arbitrary method
6220  * redirection.
6221  */
6222 inline static MonoInst*
6223 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6224                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
6225 {
6226         if (method->klass == mono_defaults.string_class) {
6227                 /* managed string allocation support */
6228                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6229                         MonoInst *iargs [2];
6230                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6231                         MonoMethod *managed_alloc = NULL;
6232
6233                         g_assert (vtable); /*Should not fail since it System.String*/
6234 #ifndef MONO_CROSS_COMPILE
6235                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
6236 #endif
6237                         if (!managed_alloc)
6238                                 return NULL;
6239                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6240                         iargs [1] = args [0];
6241                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
6242                 }
6243         }
6244         return NULL;
6245 }
6246
6247 static void
6248 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6249 {
6250         MonoInst *store, *temp;
6251         int i;
6252
6253         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6254                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6255
6256                 /*
6257                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6258                  * would be different than the MonoInst's used to represent arguments, and
6259                  * the ldelema implementation can't deal with that.
6260                  * Solution: When ldelema is used on an inline argument, create a var for 
6261                  * it, emit ldelema on that var, and emit the saving code below in
6262                  * inline_method () if needed.
6263                  */
6264                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6265                 cfg->args [i] = temp;
6266                 /* This uses cfg->args [i] which is set by the preceeding line */
6267                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6268                 store->cil_code = sp [0]->cil_code;
6269                 sp++;
6270         }
6271 }
6272
6273 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6274 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6275
6276 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6277 static gboolean
6278 check_inline_called_method_name_limit (MonoMethod *called_method)
6279 {
6280         int strncmp_result;
6281         static const char *limit = NULL;
6282         
6283         if (limit == NULL) {
6284                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6285
6286                 if (limit_string != NULL)
6287                         limit = limit_string;
6288                 else
6289                         limit = "";
6290         }
6291
6292         if (limit [0] != '\0') {
6293                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6294
6295                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6296                 g_free (called_method_name);
6297         
6298                 //return (strncmp_result <= 0);
6299                 return (strncmp_result == 0);
6300         } else {
6301                 return TRUE;
6302         }
6303 }
6304 #endif
6305
6306 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6307 static gboolean
6308 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6309 {
6310         int strncmp_result;
6311         static const char *limit = NULL;
6312         
6313         if (limit == NULL) {
6314                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6315                 if (limit_string != NULL) {
6316                         limit = limit_string;
6317                 } else {
6318                         limit = "";
6319                 }
6320         }
6321
6322         if (limit [0] != '\0') {
6323                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6324
6325                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6326                 g_free (caller_method_name);
6327         
6328                 //return (strncmp_result <= 0);
6329                 return (strncmp_result == 0);
6330         } else {
6331                 return TRUE;
6332         }
6333 }
6334 #endif
6335
6336 static void
6337 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6338 {
6339         static double r8_0 = 0.0;
6340         MonoInst *ins;
6341         int t;
6342
6343         rtype = mini_replace_type (rtype);
6344         t = rtype->type;
6345
6346         if (rtype->byref) {
6347                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6348         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6349                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6350         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6351                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6352         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6353                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6354                 ins->type = STACK_R8;
6355                 ins->inst_p0 = (void*)&r8_0;
6356                 ins->dreg = dreg;
6357                 MONO_ADD_INS (cfg->cbb, ins);
6358         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6359                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6360                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6361         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6362                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6363         } else {
6364                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6365         }
6366 }
6367
6368 static void
6369 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6370 {
6371         int t;
6372
6373         rtype = mini_replace_type (rtype);
6374         t = rtype->type;
6375
6376         if (rtype->byref) {
6377                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6378         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6379                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6380         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6381                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6382         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6383                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6384         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6385                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6386                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6387         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, rtype)) {
6388                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6389         } else {
6390                 emit_init_rvar (cfg, dreg, rtype);
6391         }
6392 }
6393
6394 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6395 static void
6396 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6397 {
6398         MonoInst *var = cfg->locals [local];
6399         if (COMPILE_SOFT_FLOAT (cfg)) {
6400                 MonoInst *store;
6401                 int reg = alloc_dreg (cfg, var->type);
6402                 emit_init_rvar (cfg, reg, type);
6403                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6404         } else {
6405                 if (init)
6406                         emit_init_rvar (cfg, var->dreg, type);
6407                 else
6408                         emit_dummy_init_rvar (cfg, var->dreg, type);
6409         }
6410 }
6411
6412 /*
6413  * inline_method:
6414  *
6415  *   Return the cost of inlining CMETHOD.
6416  */
6417 static int
6418 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6419                            guchar *ip, guint real_offset, gboolean inline_always, MonoBasicBlock **out_cbb)
6420 {
6421         MonoInst *ins, *rvar = NULL;
6422         MonoMethodHeader *cheader;
6423         MonoBasicBlock *ebblock, *sbblock;
6424         int i, costs;
6425         MonoMethod *prev_inlined_method;
6426         MonoInst **prev_locals, **prev_args;
6427         MonoType **prev_arg_types;
6428         guint prev_real_offset;
6429         GHashTable *prev_cbb_hash;
6430         MonoBasicBlock **prev_cil_offset_to_bb;
6431         MonoBasicBlock *prev_cbb;
6432         unsigned char* prev_cil_start;
6433         guint32 prev_cil_offset_to_bb_len;
6434         MonoMethod *prev_current_method;
6435         MonoGenericContext *prev_generic_context;
6436         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual = FALSE;
6437
6438         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6439
6440 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6441         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6442                 return 0;
6443 #endif
6444 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6445         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6446                 return 0;
6447 #endif
6448
6449         if (cfg->verbose_level > 2)
6450                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6451
6452         if (!cmethod->inline_info) {
6453                 cfg->stat_inlineable_methods++;
6454                 cmethod->inline_info = 1;
6455         }
6456
6457         /* allocate local variables */
6458         cheader = mono_method_get_header (cmethod);
6459
6460         if (cheader == NULL || mono_loader_get_last_error ()) {
6461                 MonoLoaderError *error = mono_loader_get_last_error ();
6462
6463                 if (cheader)
6464                         mono_metadata_free_mh (cheader);
6465                 if (inline_always && error)
6466                         mono_cfg_set_exception (cfg, error->exception_type);
6467
6468                 mono_loader_clear_error ();
6469                 return 0;
6470         }
6471
6472         /*Must verify before creating locals as it can cause the JIT to assert.*/
6473         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
6474                 mono_metadata_free_mh (cheader);
6475                 return 0;
6476         }
6477
6478         /* allocate space to store the return value */
6479         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6480                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
6481         }
6482
6483         prev_locals = cfg->locals;
6484         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
6485         for (i = 0; i < cheader->num_locals; ++i)
6486                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
6487
6488         /* allocate start and end blocks */
6489         /* This is needed so if the inline is aborted, we can clean up */
6490         NEW_BBLOCK (cfg, sbblock);
6491         sbblock->real_offset = real_offset;
6492
6493         NEW_BBLOCK (cfg, ebblock);
6494         ebblock->block_num = cfg->num_bblocks++;
6495         ebblock->real_offset = real_offset;
6496
6497         prev_args = cfg->args;
6498         prev_arg_types = cfg->arg_types;
6499         prev_inlined_method = cfg->inlined_method;
6500         cfg->inlined_method = cmethod;
6501         cfg->ret_var_set = FALSE;
6502         cfg->inline_depth ++;
6503         prev_real_offset = cfg->real_offset;
6504         prev_cbb_hash = cfg->cbb_hash;
6505         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
6506         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
6507         prev_cil_start = cfg->cil_start;
6508         prev_cbb = cfg->cbb;
6509         prev_current_method = cfg->current_method;
6510         prev_generic_context = cfg->generic_context;
6511         prev_ret_var_set = cfg->ret_var_set;
6512         prev_disable_inline = cfg->disable_inline;
6513
6514         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
6515                 virtual = TRUE;
6516
6517         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual);
6518
6519         ret_var_set = cfg->ret_var_set;
6520
6521         cfg->inlined_method = prev_inlined_method;
6522         cfg->real_offset = prev_real_offset;
6523         cfg->cbb_hash = prev_cbb_hash;
6524         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
6525         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
6526         cfg->cil_start = prev_cil_start;
6527         cfg->locals = prev_locals;
6528         cfg->args = prev_args;
6529         cfg->arg_types = prev_arg_types;
6530         cfg->current_method = prev_current_method;
6531         cfg->generic_context = prev_generic_context;
6532         cfg->ret_var_set = prev_ret_var_set;
6533         cfg->disable_inline = prev_disable_inline;
6534         cfg->inline_depth --;
6535
6536         if ((costs >= 0 && costs < 60) || inline_always) {
6537                 if (cfg->verbose_level > 2)
6538                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6539                 
6540                 cfg->stat_inlined_methods++;
6541
6542                 /* always add some code to avoid block split failures */
6543                 MONO_INST_NEW (cfg, ins, OP_NOP);
6544                 MONO_ADD_INS (prev_cbb, ins);
6545
6546                 prev_cbb->next_bb = sbblock;
6547                 link_bblock (cfg, prev_cbb, sbblock);
6548
6549                 /* 
6550                  * Get rid of the begin and end bblocks if possible to aid local
6551                  * optimizations.
6552                  */
6553                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
6554
6555                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
6556                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
6557
6558                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
6559                         MonoBasicBlock *prev = ebblock->in_bb [0];
6560                         mono_merge_basic_blocks (cfg, prev, ebblock);
6561                         cfg->cbb = prev;
6562                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
6563                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
6564                                 cfg->cbb = prev_cbb;
6565                         }
6566                 } else {
6567                         /* 
6568                          * Its possible that the rvar is set in some prev bblock, but not in others.
6569                          * (#1835).
6570                          */
6571                         if (rvar) {
6572                                 MonoBasicBlock *bb;
6573
6574                                 for (i = 0; i < ebblock->in_count; ++i) {
6575                                         bb = ebblock->in_bb [i];
6576
6577                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
6578                                                 cfg->cbb = bb;
6579
6580                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6581                                         }
6582                                 }
6583                         }
6584
6585                         cfg->cbb = ebblock;
6586                 }
6587
6588                 *out_cbb = cfg->cbb;
6589
6590                 if (rvar) {
6591                         /*
6592                          * If the inlined method contains only a throw, then the ret var is not 
6593                          * set, so set it to a dummy value.
6594                          */
6595                         if (!ret_var_set)
6596                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
6597
6598                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
6599                         *sp++ = ins;
6600                 }
6601                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6602                 return costs + 1;
6603         } else {
6604                 if (cfg->verbose_level > 2)
6605                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
6606                 cfg->exception_type = MONO_EXCEPTION_NONE;
6607                 mono_loader_clear_error ();
6608
6609                 /* This gets rid of the newly added bblocks */
6610                 cfg->cbb = prev_cbb;
6611         }
6612         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
6613         return 0;
6614 }
6615
6616 /*
6617  * Some of these comments may well be out-of-date.
6618  * Design decisions: we do a single pass over the IL code (and we do bblock 
6619  * splitting/merging in the few cases when it's required: a back jump to an IL
6620  * address that was not already seen as bblock starting point).
6621  * Code is validated as we go (full verification is still better left to metadata/verify.c).
6622  * Complex operations are decomposed in simpler ones right away. We need to let the 
6623  * arch-specific code peek and poke inside this process somehow (except when the 
6624  * optimizations can take advantage of the full semantic info of coarse opcodes).
6625  * All the opcodes of the form opcode.s are 'normalized' to opcode.
6626  * MonoInst->opcode initially is the IL opcode or some simplification of that 
6627  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
6628  * opcode with value bigger than OP_LAST.
6629  * At this point the IR can be handed over to an interpreter, a dumb code generator
6630  * or to the optimizing code generator that will translate it to SSA form.
6631  *
6632  * Profiling directed optimizations.
6633  * We may compile by default with few or no optimizations and instrument the code
6634  * or the user may indicate what methods to optimize the most either in a config file
6635  * or through repeated runs where the compiler applies offline the optimizations to 
6636  * each method and then decides if it was worth it.
6637  */
6638
6639 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
6640 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
6641 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
6642 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
6643 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
6644 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
6645 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
6646 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
6647
6648 /* offset from br.s -> br like opcodes */
6649 #define BIG_BRANCH_OFFSET 13
6650
6651 static gboolean
6652 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
6653 {
6654         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
6655
6656         return b == NULL || b == bb;
6657 }
6658
6659 static int
6660 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
6661 {
6662         unsigned char *ip = start;
6663         unsigned char *target;
6664         int i;
6665         guint cli_addr;
6666         MonoBasicBlock *bblock;
6667         const MonoOpcode *opcode;
6668
6669         while (ip < end) {
6670                 cli_addr = ip - start;
6671                 i = mono_opcode_value ((const guint8 **)&ip, end);
6672                 if (i < 0)
6673                         UNVERIFIED;
6674                 opcode = &mono_opcodes [i];
6675                 switch (opcode->argument) {
6676                 case MonoInlineNone:
6677                         ip++; 
6678                         break;
6679                 case MonoInlineString:
6680                 case MonoInlineType:
6681                 case MonoInlineField:
6682                 case MonoInlineMethod:
6683                 case MonoInlineTok:
6684                 case MonoInlineSig:
6685                 case MonoShortInlineR:
6686                 case MonoInlineI:
6687                         ip += 5;
6688                         break;
6689                 case MonoInlineVar:
6690                         ip += 3;
6691                         break;
6692                 case MonoShortInlineVar:
6693                 case MonoShortInlineI:
6694                         ip += 2;
6695                         break;
6696                 case MonoShortInlineBrTarget:
6697                         target = start + cli_addr + 2 + (signed char)ip [1];
6698                         GET_BBLOCK (cfg, bblock, target);
6699                         ip += 2;
6700                         if (ip < end)
6701                                 GET_BBLOCK (cfg, bblock, ip);
6702                         break;
6703                 case MonoInlineBrTarget:
6704                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
6705                         GET_BBLOCK (cfg, bblock, target);
6706                         ip += 5;
6707                         if (ip < end)
6708                                 GET_BBLOCK (cfg, bblock, ip);
6709                         break;
6710                 case MonoInlineSwitch: {
6711                         guint32 n = read32 (ip + 1);
6712                         guint32 j;
6713                         ip += 5;
6714                         cli_addr += 5 + 4 * n;
6715                         target = start + cli_addr;
6716                         GET_BBLOCK (cfg, bblock, target);
6717                         
6718                         for (j = 0; j < n; ++j) {
6719                                 target = start + cli_addr + (gint32)read32 (ip);
6720                                 GET_BBLOCK (cfg, bblock, target);
6721                                 ip += 4;
6722                         }
6723                         break;
6724                 }
6725                 case MonoInlineR:
6726                 case MonoInlineI8:
6727                         ip += 9;
6728                         break;
6729                 default:
6730                         g_assert_not_reached ();
6731                 }
6732
6733                 if (i == CEE_THROW) {
6734                         unsigned char *bb_start = ip - 1;
6735                         
6736                         /* Find the start of the bblock containing the throw */
6737                         bblock = NULL;
6738                         while ((bb_start >= start) && !bblock) {
6739                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
6740                                 bb_start --;
6741                         }
6742                         if (bblock)
6743                                 bblock->out_of_line = 1;
6744                 }
6745         }
6746         return 0;
6747 unverified:
6748 exception_exit:
6749         *pos = ip;
6750         return 1;
6751 }
6752
6753 static inline MonoMethod *
6754 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6755 {
6756         MonoMethod *method;
6757
6758         if (m->wrapper_type != MONO_WRAPPER_NONE) {
6759                 method = mono_method_get_wrapper_data (m, token);
6760                 if (context) {
6761                         MonoError error;
6762                         method = mono_class_inflate_generic_method_checked (method, context, &error);
6763                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
6764                 }
6765         } else {
6766                 method = mono_get_method_full (m->klass->image, token, klass, context);
6767         }
6768
6769         return method;
6770 }
6771
6772 static inline MonoMethod *
6773 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
6774 {
6775         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
6776
6777         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
6778                 return NULL;
6779
6780         return method;
6781 }
6782
6783 static inline MonoClass*
6784 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
6785 {
6786         MonoError error;
6787         MonoClass *klass;
6788
6789         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6790                 klass = mono_method_get_wrapper_data (method, token);
6791                 if (context)
6792                         klass = mono_class_inflate_generic_class (klass, context);
6793         } else {
6794                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
6795                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
6796         }
6797         if (klass)
6798                 mono_class_init (klass);
6799         return klass;
6800 }
6801
6802 static inline MonoMethodSignature*
6803 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
6804 {
6805         MonoMethodSignature *fsig;
6806
6807         if (method->wrapper_type != MONO_WRAPPER_NONE) {
6808                 MonoError error;
6809
6810                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6811                 if (context) {
6812                         fsig = mono_inflate_generic_signature (fsig, context, &error);
6813                         // FIXME:
6814                         g_assert (mono_error_ok (&error));
6815                 }
6816         } else {
6817                 fsig = mono_metadata_parse_signature (method->klass->image, token);
6818         }
6819         return fsig;
6820 }
6821
6822 /*
6823  * Returns TRUE if the JIT should abort inlining because "callee"
6824  * is influenced by security attributes.
6825  */
6826 static
6827 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6828 {
6829         guint32 result;
6830         
6831         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6832                 return TRUE;
6833         }
6834         
6835         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6836         if (result == MONO_JIT_SECURITY_OK)
6837                 return FALSE;
6838
6839         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6840                 /* Generate code to throw a SecurityException before the actual call/link */
6841                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6842                 MonoInst *args [2];
6843
6844                 NEW_ICONST (cfg, args [0], 4);
6845                 NEW_METHODCONST (cfg, args [1], caller);
6846                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6847         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6848                  /* don't hide previous results */
6849                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6850                 cfg->exception_data = result;
6851                 return TRUE;
6852         }
6853         
6854         return FALSE;
6855 }
6856
6857 static MonoMethod*
6858 throw_exception (void)
6859 {
6860         static MonoMethod *method = NULL;
6861
6862         if (!method) {
6863                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6864                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6865         }
6866         g_assert (method);
6867         return method;
6868 }
6869
6870 static void
6871 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6872 {
6873         MonoMethod *thrower = throw_exception ();
6874         MonoInst *args [1];
6875
6876         EMIT_NEW_PCONST (cfg, args [0], ex);
6877         mono_emit_method_call (cfg, thrower, args, NULL);
6878 }
6879
6880 /*
6881  * Return the original method is a wrapper is specified. We can only access 
6882  * the custom attributes from the original method.
6883  */
6884 static MonoMethod*
6885 get_original_method (MonoMethod *method)
6886 {
6887         if (method->wrapper_type == MONO_WRAPPER_NONE)
6888                 return method;
6889
6890         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6891         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6892                 return NULL;
6893
6894         /* in other cases we need to find the original method */
6895         return mono_marshal_method_from_wrapper (method);
6896 }
6897
6898 static void
6899 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6900                                           MonoBasicBlock *bblock, unsigned char *ip)
6901 {
6902         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6903         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6904         if (ex)
6905                 emit_throw_exception (cfg, ex);
6906 }
6907
6908 static void
6909 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6910                                          MonoBasicBlock *bblock, unsigned char *ip)
6911 {
6912         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6913         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6914         if (ex)
6915                 emit_throw_exception (cfg, ex);
6916 }
6917
6918 /*
6919  * Check that the IL instructions at ip are the array initialization
6920  * sequence and return the pointer to the data and the size.
6921  */
6922 static const char*
6923 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6924 {
6925         /*
6926          * newarr[System.Int32]
6927          * dup
6928          * ldtoken field valuetype ...
6929          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6930          */
6931         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6932                 MonoError error;
6933                 guint32 token = read32 (ip + 7);
6934                 guint32 field_token = read32 (ip + 2);
6935                 guint32 field_index = field_token & 0xffffff;
6936                 guint32 rva;
6937                 const char *data_ptr;
6938                 int size = 0;
6939                 MonoMethod *cmethod;
6940                 MonoClass *dummy_class;
6941                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
6942                 int dummy_align;
6943
6944                 if (!field) {
6945                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
6946                         return NULL;
6947                 }
6948
6949                 *out_field_token = field_token;
6950
6951                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6952                 if (!cmethod)
6953                         return NULL;
6954                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6955                         return NULL;
6956                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6957                 case MONO_TYPE_BOOLEAN:
6958                 case MONO_TYPE_I1:
6959                 case MONO_TYPE_U1:
6960                         size = 1; break;
6961                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6962 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6963                 case MONO_TYPE_CHAR:
6964                 case MONO_TYPE_I2:
6965                 case MONO_TYPE_U2:
6966                         size = 2; break;
6967                 case MONO_TYPE_I4:
6968                 case MONO_TYPE_U4:
6969                 case MONO_TYPE_R4:
6970                         size = 4; break;
6971                 case MONO_TYPE_R8:
6972                 case MONO_TYPE_I8:
6973                 case MONO_TYPE_U8:
6974                         size = 8; break;
6975 #endif
6976                 default:
6977                         return NULL;
6978                 }
6979                 size *= len;
6980                 if (size > mono_type_size (field->type, &dummy_align))
6981                     return NULL;
6982                 *out_size = size;
6983                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6984                 if (!image_is_dynamic (method->klass->image)) {
6985                         field_index = read32 (ip + 2) & 0xffffff;
6986                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6987                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6988                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6989                         /* for aot code we do the lookup on load */
6990                         if (aot && data_ptr)
6991                                 return GUINT_TO_POINTER (rva);
6992                 } else {
6993                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6994                         g_assert (!aot);
6995                         data_ptr = mono_field_get_data (field);
6996                 }
6997                 return data_ptr;
6998         }
6999         return NULL;
7000 }
7001
7002 static void
7003 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7004 {
7005         char *method_fname = mono_method_full_name (method, TRUE);
7006         char *method_code;
7007         MonoMethodHeader *header = mono_method_get_header (method);
7008
7009         if (header->code_size == 0)
7010                 method_code = g_strdup ("method body is empty.");
7011         else
7012                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7013         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7014         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7015         g_free (method_fname);
7016         g_free (method_code);
7017         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7018 }
7019
7020 static void
7021 set_exception_object (MonoCompile *cfg, MonoException *exception)
7022 {
7023         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7024         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
7025         cfg->exception_ptr = exception;
7026 }
7027
7028 static void
7029 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7030 {
7031         MonoInst *ins;
7032         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7033         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7034                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7035                 /* Optimize reg-reg moves away */
7036                 /* 
7037                  * Can't optimize other opcodes, since sp[0] might point to
7038                  * the last ins of a decomposed opcode.
7039                  */
7040                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7041         } else {
7042                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7043         }
7044 }
7045
7046 /*
7047  * ldloca inhibits many optimizations so try to get rid of it in common
7048  * cases.
7049  */
7050 static inline unsigned char *
7051 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7052 {
7053         int local, token;
7054         MonoClass *klass;
7055         MonoType *type;
7056
7057         if (size == 1) {
7058                 local = ip [1];
7059                 ip += 2;
7060         } else {
7061                 local = read16 (ip + 2);
7062                 ip += 4;
7063         }
7064         
7065         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7066                 /* From the INITOBJ case */
7067                 token = read32 (ip + 2);
7068                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7069                 CHECK_TYPELOAD (klass);
7070                 type = mini_replace_type (&klass->byval_arg);
7071                 emit_init_local (cfg, local, type, TRUE);
7072                 return ip + 6;
7073         }
7074  exception_exit:
7075         return NULL;
7076 }
7077
7078 static gboolean
7079 is_exception_class (MonoClass *class)
7080 {
7081         while (class) {
7082                 if (class == mono_defaults.exception_class)
7083                         return TRUE;
7084                 class = class->parent;
7085         }
7086         return FALSE;
7087 }
7088
7089 /*
7090  * is_jit_optimizer_disabled:
7091  *
7092  *   Determine whenever M's assembly has a DebuggableAttribute with the
7093  * IsJITOptimizerDisabled flag set.
7094  */
7095 static gboolean
7096 is_jit_optimizer_disabled (MonoMethod *m)
7097 {
7098         MonoAssembly *ass = m->klass->image->assembly;
7099         MonoCustomAttrInfo* attrs;
7100         static MonoClass *klass;
7101         int i;
7102         gboolean val = FALSE;
7103
7104         g_assert (ass);
7105         if (ass->jit_optimizer_disabled_inited)
7106                 return ass->jit_optimizer_disabled;
7107
7108         if (!klass)
7109                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7110         if (!klass) {
7111                 /* Linked away */
7112                 ass->jit_optimizer_disabled = FALSE;
7113                 mono_memory_barrier ();
7114                 ass->jit_optimizer_disabled_inited = TRUE;
7115                 return FALSE;
7116         }
7117
7118         attrs = mono_custom_attrs_from_assembly (ass);
7119         if (attrs) {
7120                 for (i = 0; i < attrs->num_attrs; ++i) {
7121                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7122                         const gchar *p;
7123                         int len;
7124                         MonoMethodSignature *sig;
7125
7126                         if (!attr->ctor || attr->ctor->klass != klass)
7127                                 continue;
7128                         /* Decode the attribute. See reflection.c */
7129                         len = attr->data_size;
7130                         p = (const char*)attr->data;
7131                         g_assert (read16 (p) == 0x0001);
7132                         p += 2;
7133
7134                         // FIXME: Support named parameters
7135                         sig = mono_method_signature (attr->ctor);
7136                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7137                                 continue;
7138                         /* Two boolean arguments */
7139                         p ++;
7140                         val = *p;
7141                 }
7142                 mono_custom_attrs_free (attrs);
7143         }
7144
7145         ass->jit_optimizer_disabled = val;
7146         mono_memory_barrier ();
7147         ass->jit_optimizer_disabled_inited = TRUE;
7148
7149         return val;
7150 }
7151
7152 static gboolean
7153 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7154 {
7155         gboolean supported_tail_call;
7156         int i;
7157
7158 #ifdef MONO_ARCH_HAVE_OP_TAIL_CALL
7159         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7160 #else
7161         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
7162 #endif
7163
7164         for (i = 0; i < fsig->param_count; ++i) {
7165                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7166                         /* These can point to the current method's stack */
7167                         supported_tail_call = FALSE;
7168         }
7169         if (fsig->hasthis && cmethod->klass->valuetype)
7170                 /* this might point to the current method's stack */
7171                 supported_tail_call = FALSE;
7172         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7173                 supported_tail_call = FALSE;
7174         if (cfg->method->save_lmf)
7175                 supported_tail_call = FALSE;
7176         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7177                 supported_tail_call = FALSE;
7178         if (call_opcode != CEE_CALL)
7179                 supported_tail_call = FALSE;
7180
7181         /* Debugging support */
7182 #if 0
7183         if (supported_tail_call) {
7184                 if (!mono_debug_count ())
7185                         supported_tail_call = FALSE;
7186         }
7187 #endif
7188
7189         return supported_tail_call;
7190 }
7191
7192 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
7193  * it to the thread local value based on the tls_offset field. Every other kind of access to
7194  * the field causes an assert.
7195  */
7196 static gboolean
7197 is_magic_tls_access (MonoClassField *field)
7198 {
7199         if (strcmp (field->name, "tlsdata"))
7200                 return FALSE;
7201         if (strcmp (field->parent->name, "ThreadLocal`1"))
7202                 return FALSE;
7203         return field->parent->image == mono_defaults.corlib;
7204 }
7205
7206 /* emits the code needed to access a managed tls var (like ThreadStatic)
7207  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
7208  * pointer for the current thread.
7209  * Returns the MonoInst* representing the address of the tls var.
7210  */
7211 static MonoInst*
7212 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
7213 {
7214         MonoInst *addr;
7215         int static_data_reg, array_reg, dreg;
7216         int offset2_reg, idx_reg;
7217         // inlined access to the tls data
7218         // idx = (offset >> 24) - 1;
7219         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
7220         static_data_reg = alloc_ireg (cfg);
7221         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
7222         idx_reg = alloc_ireg (cfg);
7223         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
7224         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
7225         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
7226         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
7227         array_reg = alloc_ireg (cfg);
7228         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
7229         offset2_reg = alloc_ireg (cfg);
7230         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
7231         dreg = alloc_ireg (cfg);
7232         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
7233         return addr;
7234 }
7235
7236 /*
7237  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
7238  * this address is cached per-method in cached_tls_addr.
7239  */
7240 static MonoInst*
7241 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
7242 {
7243         MonoInst *load, *addr, *temp, *store, *thread_ins;
7244         MonoClassField *offset_field;
7245
7246         if (*cached_tls_addr) {
7247                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
7248                 return addr;
7249         }
7250         thread_ins = mono_get_thread_intrinsic (cfg);
7251         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
7252
7253         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
7254         if (thread_ins) {
7255                 MONO_ADD_INS (cfg->cbb, thread_ins);
7256         } else {
7257                 MonoMethod *thread_method;
7258                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
7259                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
7260         }
7261         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
7262         addr->klass = mono_class_from_mono_type (tls_field->type);
7263         addr->type = STACK_MP;
7264         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
7265         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
7266
7267         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
7268         return addr;
7269 }
7270
7271 /*
7272  * handle_ctor_call:
7273  *
7274  *   Handle calls made to ctors from NEWOBJ opcodes.
7275  *
7276  *   REF_BBLOCK will point to the current bblock after the call.
7277  */
7278 static void
7279 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7280                                   MonoInst **sp, guint8 *ip, MonoBasicBlock **ref_bblock, int *inline_costs)
7281 {
7282         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7283         MonoBasicBlock *bblock = *ref_bblock;
7284
7285         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7286                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7287                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7288                         mono_class_vtable (cfg->domain, cmethod->klass);
7289                         CHECK_TYPELOAD (cmethod->klass);
7290
7291                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7292                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7293                 } else {
7294                         if (context_used) {
7295                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7296                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7297                         } else {
7298                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7299
7300                                 CHECK_TYPELOAD (cmethod->klass);
7301                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7302                         }
7303                 }
7304         }
7305
7306         /* Avoid virtual calls to ctors if possible */
7307         if (mono_class_is_marshalbyref (cmethod->klass))
7308                 callvirt_this_arg = sp [0];
7309
7310         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7311                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7312                 CHECK_CFG_EXCEPTION;
7313         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7314                            mono_method_check_inlining (cfg, cmethod) &&
7315                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7316                 int costs;
7317
7318                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE, &bblock))) {
7319                         cfg->real_offset += 5;
7320
7321                         *inline_costs += costs - 5;
7322                         *ref_bblock = bblock;
7323                 } else {
7324                         INLINE_FAILURE ("inline failure");
7325                         // FIXME-VT: Clean this up
7326                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7327                                 GSHAREDVT_FAILURE(*ip);
7328                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7329                 }
7330         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
7331                 MonoInst *addr;
7332
7333                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7334                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7335         } else if (context_used &&
7336                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7337                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7338                 MonoInst *cmethod_addr;
7339
7340                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7341
7342                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7343                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7344
7345                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7346         } else {
7347                 INLINE_FAILURE ("ctor call");
7348                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7349                                                                                   callvirt_this_arg, NULL, vtable_arg);
7350         }
7351  exception_exit:
7352         return;
7353 }
7354
7355 /*
7356  * mono_method_to_ir:
7357  *
7358  *   Translate the .net IL into linear IR.
7359  */
7360 int
7361 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7362                    MonoInst *return_var, MonoInst **inline_args, 
7363                    guint inline_offset, gboolean is_virtual_call)
7364 {
7365         MonoError error;
7366         MonoInst *ins, **sp, **stack_start;
7367         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
7368         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7369         MonoMethod *cmethod, *method_definition;
7370         MonoInst **arg_array;
7371         MonoMethodHeader *header;
7372         MonoImage *image;
7373         guint32 token, ins_flag;
7374         MonoClass *klass;
7375         MonoClass *constrained_call = NULL;
7376         unsigned char *ip, *end, *target, *err_pos;
7377         MonoMethodSignature *sig;
7378         MonoGenericContext *generic_context = NULL;
7379         MonoGenericContainer *generic_container = NULL;
7380         MonoType **param_types;
7381         int i, n, start_new_bblock, dreg;
7382         int num_calls = 0, inline_costs = 0;
7383         int breakpoint_id = 0;
7384         guint num_args;
7385         MonoBoolean security, pinvoke;
7386         MonoSecurityManager* secman = NULL;
7387         MonoDeclSecurityActions actions;
7388         GSList *class_inits = NULL;
7389         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7390         int context_used;
7391         gboolean init_locals, seq_points, skip_dead_blocks;
7392         gboolean sym_seq_points = FALSE;
7393         MonoInst *cached_tls_addr = NULL;
7394         MonoDebugMethodInfo *minfo;
7395         MonoBitSet *seq_point_locs = NULL;
7396         MonoBitSet *seq_point_set_locs = NULL;
7397
7398         cfg->disable_inline = is_jit_optimizer_disabled (method);
7399
7400         /* serialization and xdomain stuff may need access to private fields and methods */
7401         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7402         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7403         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7404         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7405         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7406         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7407
7408         dont_verify |= mono_security_smcs_hack_enabled ();
7409
7410         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7411         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7412         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7413         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7414         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7415
7416         image = method->klass->image;
7417         header = mono_method_get_header (method);
7418         if (!header) {
7419                 MonoLoaderError *error;
7420
7421                 if ((error = mono_loader_get_last_error ())) {
7422                         mono_cfg_set_exception (cfg, error->exception_type);
7423                 } else {
7424                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7425                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7426                 }
7427                 goto exception_exit;
7428         }
7429         generic_container = mono_method_get_generic_container (method);
7430         sig = mono_method_signature (method);
7431         num_args = sig->hasthis + sig->param_count;
7432         ip = (unsigned char*)header->code;
7433         cfg->cil_start = ip;
7434         end = ip + header->code_size;
7435         cfg->stat_cil_code_size += header->code_size;
7436
7437         seq_points = cfg->gen_seq_points && cfg->method == method;
7438 #ifdef PLATFORM_ANDROID
7439         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
7440 #endif
7441
7442         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7443                 /* We could hit a seq point before attaching to the JIT (#8338) */
7444                 seq_points = FALSE;
7445         }
7446
7447         if (cfg->gen_seq_points_debug_data && cfg->method == method) {
7448                 minfo = mono_debug_lookup_method (method);
7449                 if (minfo) {
7450                         int i, n_il_offsets;
7451                         int *il_offsets;
7452                         int *line_numbers;
7453
7454                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL, NULL, NULL);
7455                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7456                         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);
7457                         sym_seq_points = TRUE;
7458                         for (i = 0; i < n_il_offsets; ++i) {
7459                                 if (il_offsets [i] < header->code_size)
7460                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
7461                         }
7462                         g_free (il_offsets);
7463                         g_free (line_numbers);
7464                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7465                         /* Methods without line number info like auto-generated property accessors */
7466                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7467                         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);
7468                         sym_seq_points = TRUE;
7469                 }
7470         }
7471
7472         /* 
7473          * Methods without init_locals set could cause asserts in various passes
7474          * (#497220). To work around this, we emit dummy initialization opcodes
7475          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7476          * on some platforms.
7477          */
7478         if ((cfg->opt & MONO_OPT_UNSAFE) && ARCH_HAVE_DUMMY_INIT)
7479                 init_locals = header->init_locals;
7480         else
7481                 init_locals = TRUE;
7482
7483         method_definition = method;
7484         while (method_definition->is_inflated) {
7485                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7486                 method_definition = imethod->declaring;
7487         }
7488
7489         /* SkipVerification is not allowed if core-clr is enabled */
7490         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7491                 dont_verify = TRUE;
7492                 dont_verify_stloc = TRUE;
7493         }
7494
7495         if (sig->is_inflated)
7496                 generic_context = mono_method_get_context (method);
7497         else if (generic_container)
7498                 generic_context = &generic_container->context;
7499         cfg->generic_context = generic_context;
7500
7501         if (!cfg->generic_sharing_context)
7502                 g_assert (!sig->has_type_parameters);
7503
7504         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7505                 g_assert (method->is_inflated);
7506                 g_assert (mono_method_get_context (method)->method_inst);
7507         }
7508         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7509                 g_assert (sig->generic_param_count);
7510
7511         if (cfg->method == method) {
7512                 cfg->real_offset = 0;
7513         } else {
7514                 cfg->real_offset = inline_offset;
7515         }
7516
7517         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7518         cfg->cil_offset_to_bb_len = header->code_size;
7519
7520         cfg->current_method = method;
7521
7522         if (cfg->verbose_level > 2)
7523                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7524
7525         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7526         if (sig->hasthis)
7527                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7528         for (n = 0; n < sig->param_count; ++n)
7529                 param_types [n + sig->hasthis] = sig->params [n];
7530         cfg->arg_types = param_types;
7531
7532         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7533         if (cfg->method == method) {
7534
7535                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7536                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7537
7538                 /* ENTRY BLOCK */
7539                 NEW_BBLOCK (cfg, start_bblock);
7540                 cfg->bb_entry = start_bblock;
7541                 start_bblock->cil_code = NULL;
7542                 start_bblock->cil_length = 0;
7543 #if defined(__native_client_codegen__)
7544                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
7545                 ins->dreg = alloc_dreg (cfg, STACK_I4);
7546                 MONO_ADD_INS (start_bblock, ins);
7547 #endif
7548
7549                 /* EXIT BLOCK */
7550                 NEW_BBLOCK (cfg, end_bblock);
7551                 cfg->bb_exit = end_bblock;
7552                 end_bblock->cil_code = NULL;
7553                 end_bblock->cil_length = 0;
7554                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7555                 g_assert (cfg->num_bblocks == 2);
7556
7557                 arg_array = cfg->args;
7558
7559                 if (header->num_clauses) {
7560                         cfg->spvars = g_hash_table_new (NULL, NULL);
7561                         cfg->exvars = g_hash_table_new (NULL, NULL);
7562                 }
7563                 /* handle exception clauses */
7564                 for (i = 0; i < header->num_clauses; ++i) {
7565                         MonoBasicBlock *try_bb;
7566                         MonoExceptionClause *clause = &header->clauses [i];
7567                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
7568                         try_bb->real_offset = clause->try_offset;
7569                         try_bb->try_start = TRUE;
7570                         try_bb->region = ((i + 1) << 8) | clause->flags;
7571                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
7572                         tblock->real_offset = clause->handler_offset;
7573                         tblock->flags |= BB_EXCEPTION_HANDLER;
7574
7575                         /*
7576                          * Linking the try block with the EH block hinders inlining as we won't be able to 
7577                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
7578                          */
7579                         if (COMPILE_LLVM (cfg))
7580                                 link_bblock (cfg, try_bb, tblock);
7581
7582                         if (*(ip + clause->handler_offset) == CEE_POP)
7583                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
7584
7585                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
7586                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
7587                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
7588                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7589                                 MONO_ADD_INS (tblock, ins);
7590
7591                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
7592                                         /* finally clauses already have a seq point */
7593                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
7594                                         MONO_ADD_INS (tblock, ins);
7595                                 }
7596
7597                                 /* todo: is a fault block unsafe to optimize? */
7598                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
7599                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
7600                         }
7601
7602
7603                         /*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);
7604                           while (p < end) {
7605                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
7606                           }*/
7607                         /* catch and filter blocks get the exception object on the stack */
7608                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
7609                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7610                                 MonoInst *dummy_use;
7611
7612                                 /* mostly like handle_stack_args (), but just sets the input args */
7613                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
7614                                 tblock->in_scount = 1;
7615                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7616                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7617
7618                                 /* 
7619                                  * Add a dummy use for the exvar so its liveness info will be
7620                                  * correct.
7621                                  */
7622                                 cfg->cbb = tblock;
7623                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
7624                                 
7625                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
7626                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
7627                                         tblock->flags |= BB_EXCEPTION_HANDLER;
7628                                         tblock->real_offset = clause->data.filter_offset;
7629                                         tblock->in_scount = 1;
7630                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
7631                                         /* The filter block shares the exvar with the handler block */
7632                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
7633                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
7634                                         MONO_ADD_INS (tblock, ins);
7635                                 }
7636                         }
7637
7638                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
7639                                         clause->data.catch_class &&
7640                                         cfg->generic_sharing_context &&
7641                                         mono_class_check_context_used (clause->data.catch_class)) {
7642                                 /*
7643                                  * In shared generic code with catch
7644                                  * clauses containing type variables
7645                                  * the exception handling code has to
7646                                  * be able to get to the rgctx.
7647                                  * Therefore we have to make sure that
7648                                  * the vtable/mrgctx argument (for
7649                                  * static or generic methods) or the
7650                                  * "this" argument (for non-static
7651                                  * methods) are live.
7652                                  */
7653                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7654                                                 mini_method_get_context (method)->method_inst ||
7655                                                 method->klass->valuetype) {
7656                                         mono_get_vtable_var (cfg);
7657                                 } else {
7658                                         MonoInst *dummy_use;
7659
7660                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
7661                                 }
7662                         }
7663                 }
7664         } else {
7665                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
7666                 cfg->cbb = start_bblock;
7667                 cfg->args = arg_array;
7668                 mono_save_args (cfg, sig, inline_args);
7669         }
7670
7671         /* FIRST CODE BLOCK */
7672         NEW_BBLOCK (cfg, bblock);
7673         bblock->cil_code = ip;
7674         cfg->cbb = bblock;
7675         cfg->ip = ip;
7676
7677         ADD_BBLOCK (cfg, bblock);
7678
7679         if (cfg->method == method) {
7680                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
7681                 if (breakpoint_id) {
7682                         MONO_INST_NEW (cfg, ins, OP_BREAK);
7683                         MONO_ADD_INS (bblock, ins);
7684                 }
7685         }
7686
7687         if (mono_security_cas_enabled ())
7688                 secman = mono_security_manager_get_methods ();
7689
7690         security = (secman && mono_security_method_has_declsec (method));
7691         /* at this point having security doesn't mean we have any code to generate */
7692         if (security && (cfg->method == method)) {
7693                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
7694                  * And we do not want to enter the next section (with allocation) if we
7695                  * have nothing to generate */
7696                 security = mono_declsec_get_demands (method, &actions);
7697         }
7698
7699         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
7700         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
7701         if (pinvoke) {
7702                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7703                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7704                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
7705
7706                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
7707                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7708                                 pinvoke = FALSE;
7709                         }
7710                         if (custom)
7711                                 mono_custom_attrs_free (custom);
7712
7713                         if (pinvoke) {
7714                                 custom = mono_custom_attrs_from_class (wrapped->klass);
7715                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
7716                                         pinvoke = FALSE;
7717                                 }
7718                                 if (custom)
7719                                         mono_custom_attrs_free (custom);
7720                         }
7721                 } else {
7722                         /* not a P/Invoke after all */
7723                         pinvoke = FALSE;
7724                 }
7725         }
7726         
7727         /* we use a separate basic block for the initialization code */
7728         NEW_BBLOCK (cfg, init_localsbb);
7729         cfg->bb_init = init_localsbb;
7730         init_localsbb->real_offset = cfg->real_offset;
7731         start_bblock->next_bb = init_localsbb;
7732         init_localsbb->next_bb = bblock;
7733         link_bblock (cfg, start_bblock, init_localsbb);
7734         link_bblock (cfg, init_localsbb, bblock);
7735                 
7736         cfg->cbb = init_localsbb;
7737
7738         if (cfg->gsharedvt && cfg->method == method) {
7739                 MonoGSharedVtMethodInfo *info;
7740                 MonoInst *var, *locals_var;
7741                 int dreg;
7742
7743                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
7744                 info->method = cfg->method;
7745                 info->count_entries = 16;
7746                 info->entries = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
7747                 cfg->gsharedvt_info = info;
7748
7749                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7750                 /* prevent it from being register allocated */
7751                 //var->flags |= MONO_INST_VOLATILE;
7752                 cfg->gsharedvt_info_var = var;
7753
7754                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
7755                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
7756
7757                 /* Allocate locals */
7758                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7759                 /* prevent it from being register allocated */
7760                 //locals_var->flags |= MONO_INST_VOLATILE;
7761                 cfg->gsharedvt_locals_var = locals_var;
7762
7763                 dreg = alloc_ireg (cfg);
7764                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
7765
7766                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
7767                 ins->dreg = locals_var->dreg;
7768                 ins->sreg1 = dreg;
7769                 MONO_ADD_INS (cfg->cbb, ins);
7770                 cfg->gsharedvt_locals_var_ins = ins;
7771                 
7772                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
7773                 /*
7774                 if (init_locals)
7775                         ins->flags |= MONO_INST_INIT;
7776                 */
7777         }
7778
7779         /* at this point we know, if security is TRUE, that some code needs to be generated */
7780         if (security && (cfg->method == method)) {
7781                 MonoInst *args [2];
7782
7783                 cfg->stat_cas_demand_generation++;
7784
7785                 if (actions.demand.blob) {
7786                         /* Add code for SecurityAction.Demand */
7787                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
7788                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
7789                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7790                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7791                 }
7792                 if (actions.noncasdemand.blob) {
7793                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
7794                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
7795                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
7796                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
7797                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
7798                         mono_emit_method_call (cfg, secman->demand, args, NULL);
7799                 }
7800                 if (actions.demandchoice.blob) {
7801                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
7802                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
7803                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
7804                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
7805                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
7806                 }
7807         }
7808
7809         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
7810         if (pinvoke) {
7811                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
7812         }
7813
7814         if (mono_security_core_clr_enabled ()) {
7815                 /* check if this is native code, e.g. an icall or a p/invoke */
7816                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
7817                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
7818                         if (wrapped) {
7819                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
7820                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
7821
7822                                 /* if this ia a native call then it can only be JITted from platform code */
7823                                 if ((icall || pinvk) && method->klass && method->klass->image) {
7824                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
7825                                                 MonoException *ex = icall ? mono_get_exception_security () : 
7826                                                         mono_get_exception_method_access ();
7827                                                 emit_throw_exception (cfg, ex);
7828                                         }
7829                                 }
7830                         }
7831                 }
7832         }
7833
7834         CHECK_CFG_EXCEPTION;
7835
7836         if (header->code_size == 0)
7837                 UNVERIFIED;
7838
7839         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
7840                 ip = err_pos;
7841                 UNVERIFIED;
7842         }
7843
7844         if (cfg->method == method)
7845                 mono_debug_init_method (cfg, bblock, breakpoint_id);
7846
7847         for (n = 0; n < header->num_locals; ++n) {
7848                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
7849                         UNVERIFIED;
7850         }
7851         class_inits = NULL;
7852
7853         /* We force the vtable variable here for all shared methods
7854            for the possibility that they might show up in a stack
7855            trace where their exact instantiation is needed. */
7856         if (cfg->generic_sharing_context && method == cfg->method) {
7857                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
7858                                 mini_method_get_context (method)->method_inst ||
7859                                 method->klass->valuetype) {
7860                         mono_get_vtable_var (cfg);
7861                 } else {
7862                         /* FIXME: Is there a better way to do this?
7863                            We need the variable live for the duration
7864                            of the whole method. */
7865                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
7866                 }
7867         }
7868
7869         /* add a check for this != NULL to inlined methods */
7870         if (is_virtual_call) {
7871                 MonoInst *arg_ins;
7872
7873                 NEW_ARGLOAD (cfg, arg_ins, 0);
7874                 MONO_ADD_INS (cfg->cbb, arg_ins);
7875                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
7876         }
7877
7878         skip_dead_blocks = !dont_verify;
7879         if (skip_dead_blocks) {
7880                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
7881                 CHECK_CFG_ERROR;
7882                 g_assert (bb);
7883         }
7884
7885         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
7886         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
7887
7888         ins_flag = 0;
7889         start_new_bblock = 0;
7890         cfg->cbb = bblock;
7891         while (ip < end) {
7892                 if (cfg->method == method)
7893                         cfg->real_offset = ip - header->code;
7894                 else
7895                         cfg->real_offset = inline_offset;
7896                 cfg->ip = ip;
7897
7898                 context_used = 0;
7899                 
7900                 if (start_new_bblock) {
7901                         bblock->cil_length = ip - bblock->cil_code;
7902                         if (start_new_bblock == 2) {
7903                                 g_assert (ip == tblock->cil_code);
7904                         } else {
7905                                 GET_BBLOCK (cfg, tblock, ip);
7906                         }
7907                         bblock->next_bb = tblock;
7908                         bblock = tblock;
7909                         cfg->cbb = bblock;
7910                         start_new_bblock = 0;
7911                         for (i = 0; i < bblock->in_scount; ++i) {
7912                                 if (cfg->verbose_level > 3)
7913                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7914                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7915                                 *sp++ = ins;
7916                         }
7917                         if (class_inits)
7918                                 g_slist_free (class_inits);
7919                         class_inits = NULL;
7920                 } else {
7921                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7922                                 link_bblock (cfg, bblock, tblock);
7923                                 if (sp != stack_start) {
7924                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7925                                         sp = stack_start;
7926                                         CHECK_UNVERIFIABLE (cfg);
7927                                 }
7928                                 bblock->next_bb = tblock;
7929                                 bblock = tblock;
7930                                 cfg->cbb = bblock;
7931                                 for (i = 0; i < bblock->in_scount; ++i) {
7932                                         if (cfg->verbose_level > 3)
7933                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7934                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7935                                         *sp++ = ins;
7936                                 }
7937                                 g_slist_free (class_inits);
7938                                 class_inits = NULL;
7939                         }
7940                 }
7941
7942                 if (skip_dead_blocks) {
7943                         int ip_offset = ip - header->code;
7944
7945                         if (ip_offset == bb->end)
7946                                 bb = bb->next;
7947
7948                         if (bb->dead) {
7949                                 int op_size = mono_opcode_size (ip, end);
7950                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7951
7952                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7953
7954                                 if (ip_offset + op_size == bb->end) {
7955                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7956                                         MONO_ADD_INS (bblock, ins);
7957                                         start_new_bblock = 1;
7958                                 }
7959
7960                                 ip += op_size;
7961                                 continue;
7962                         }
7963                 }
7964                 /*
7965                  * Sequence points are points where the debugger can place a breakpoint.
7966                  * Currently, we generate these automatically at points where the IL
7967                  * stack is empty.
7968                  */
7969                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7970                         /*
7971                          * Make methods interruptable at the beginning, and at the targets of
7972                          * backward branches.
7973                          * Also, do this at the start of every bblock in methods with clauses too,
7974                          * to be able to handle instructions with inprecise control flow like
7975                          * throw/endfinally.
7976                          * Backward branches are handled at the end of method-to-ir ().
7977                          */
7978                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7979
7980                         /* Avoid sequence points on empty IL like .volatile */
7981                         // FIXME: Enable this
7982                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7983                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7984                         if (sp != stack_start)
7985                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7986                         MONO_ADD_INS (cfg->cbb, ins);
7987
7988                         if (sym_seq_points)
7989                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7990                 }
7991
7992                 bblock->real_offset = cfg->real_offset;
7993
7994                 if ((cfg->method == method) && cfg->coverage_info) {
7995                         guint32 cil_offset = ip - header->code;
7996                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7997
7998                         /* TODO: Use an increment here */
7999 #if defined(TARGET_X86)
8000                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8001                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8002                         ins->inst_imm = 1;
8003                         MONO_ADD_INS (cfg->cbb, ins);
8004 #else
8005                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8006                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8007 #endif
8008                 }
8009
8010                 if (cfg->verbose_level > 3)
8011                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8012
8013                 switch (*ip) {
8014                 case CEE_NOP:
8015                         if (seq_points && !sym_seq_points && sp != stack_start) {
8016                                 /*
8017                                  * The C# compiler uses these nops to notify the JIT that it should
8018                                  * insert seq points.
8019                                  */
8020                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8021                                 MONO_ADD_INS (cfg->cbb, ins);
8022                         }
8023                         if (cfg->keep_cil_nops)
8024                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8025                         else
8026                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8027                         ip++;
8028                         MONO_ADD_INS (bblock, ins);
8029                         break;
8030                 case CEE_BREAK:
8031                         if (should_insert_brekpoint (cfg->method)) {
8032                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8033                         } else {
8034                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8035                         }
8036                         ip++;
8037                         MONO_ADD_INS (bblock, ins);
8038                         break;
8039                 case CEE_LDARG_0:
8040                 case CEE_LDARG_1:
8041                 case CEE_LDARG_2:
8042                 case CEE_LDARG_3:
8043                         CHECK_STACK_OVF (1);
8044                         n = (*ip)-CEE_LDARG_0;
8045                         CHECK_ARG (n);
8046                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8047                         ip++;
8048                         *sp++ = ins;
8049                         break;
8050                 case CEE_LDLOC_0:
8051                 case CEE_LDLOC_1:
8052                 case CEE_LDLOC_2:
8053                 case CEE_LDLOC_3:
8054                         CHECK_STACK_OVF (1);
8055                         n = (*ip)-CEE_LDLOC_0;
8056                         CHECK_LOCAL (n);
8057                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8058                         ip++;
8059                         *sp++ = ins;
8060                         break;
8061                 case CEE_STLOC_0:
8062                 case CEE_STLOC_1:
8063                 case CEE_STLOC_2:
8064                 case CEE_STLOC_3: {
8065                         CHECK_STACK (1);
8066                         n = (*ip)-CEE_STLOC_0;
8067                         CHECK_LOCAL (n);
8068                         --sp;
8069                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8070                                 UNVERIFIED;
8071                         emit_stloc_ir (cfg, sp, header, n);
8072                         ++ip;
8073                         inline_costs += 1;
8074                         break;
8075                         }
8076                 case CEE_LDARG_S:
8077                         CHECK_OPSIZE (2);
8078                         CHECK_STACK_OVF (1);
8079                         n = ip [1];
8080                         CHECK_ARG (n);
8081                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8082                         *sp++ = ins;
8083                         ip += 2;
8084                         break;
8085                 case CEE_LDARGA_S:
8086                         CHECK_OPSIZE (2);
8087                         CHECK_STACK_OVF (1);
8088                         n = ip [1];
8089                         CHECK_ARG (n);
8090                         NEW_ARGLOADA (cfg, ins, n);
8091                         MONO_ADD_INS (cfg->cbb, ins);
8092                         *sp++ = ins;
8093                         ip += 2;
8094                         break;
8095                 case CEE_STARG_S:
8096                         CHECK_OPSIZE (2);
8097                         CHECK_STACK (1);
8098                         --sp;
8099                         n = ip [1];
8100                         CHECK_ARG (n);
8101                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8102                                 UNVERIFIED;
8103                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8104                         ip += 2;
8105                         break;
8106                 case CEE_LDLOC_S:
8107                         CHECK_OPSIZE (2);
8108                         CHECK_STACK_OVF (1);
8109                         n = ip [1];
8110                         CHECK_LOCAL (n);
8111                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8112                         *sp++ = ins;
8113                         ip += 2;
8114                         break;
8115                 case CEE_LDLOCA_S: {
8116                         unsigned char *tmp_ip;
8117                         CHECK_OPSIZE (2);
8118                         CHECK_STACK_OVF (1);
8119                         CHECK_LOCAL (ip [1]);
8120
8121                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8122                                 ip = tmp_ip;
8123                                 inline_costs += 1;
8124                                 break;
8125                         }
8126
8127                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8128                         *sp++ = ins;
8129                         ip += 2;
8130                         break;
8131                 }
8132                 case CEE_STLOC_S:
8133                         CHECK_OPSIZE (2);
8134                         CHECK_STACK (1);
8135                         --sp;
8136                         CHECK_LOCAL (ip [1]);
8137                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8138                                 UNVERIFIED;
8139                         emit_stloc_ir (cfg, sp, header, ip [1]);
8140                         ip += 2;
8141                         inline_costs += 1;
8142                         break;
8143                 case CEE_LDNULL:
8144                         CHECK_STACK_OVF (1);
8145                         EMIT_NEW_PCONST (cfg, ins, NULL);
8146                         ins->type = STACK_OBJ;
8147                         ++ip;
8148                         *sp++ = ins;
8149                         break;
8150                 case CEE_LDC_I4_M1:
8151                         CHECK_STACK_OVF (1);
8152                         EMIT_NEW_ICONST (cfg, ins, -1);
8153                         ++ip;
8154                         *sp++ = ins;
8155                         break;
8156                 case CEE_LDC_I4_0:
8157                 case CEE_LDC_I4_1:
8158                 case CEE_LDC_I4_2:
8159                 case CEE_LDC_I4_3:
8160                 case CEE_LDC_I4_4:
8161                 case CEE_LDC_I4_5:
8162                 case CEE_LDC_I4_6:
8163                 case CEE_LDC_I4_7:
8164                 case CEE_LDC_I4_8:
8165                         CHECK_STACK_OVF (1);
8166                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8167                         ++ip;
8168                         *sp++ = ins;
8169                         break;
8170                 case CEE_LDC_I4_S:
8171                         CHECK_OPSIZE (2);
8172                         CHECK_STACK_OVF (1);
8173                         ++ip;
8174                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8175                         ++ip;
8176                         *sp++ = ins;
8177                         break;
8178                 case CEE_LDC_I4:
8179                         CHECK_OPSIZE (5);
8180                         CHECK_STACK_OVF (1);
8181                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8182                         ip += 5;
8183                         *sp++ = ins;
8184                         break;
8185                 case CEE_LDC_I8:
8186                         CHECK_OPSIZE (9);
8187                         CHECK_STACK_OVF (1);
8188                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8189                         ins->type = STACK_I8;
8190                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8191                         ++ip;
8192                         ins->inst_l = (gint64)read64 (ip);
8193                         MONO_ADD_INS (bblock, ins);
8194                         ip += 8;
8195                         *sp++ = ins;
8196                         break;
8197                 case CEE_LDC_R4: {
8198                         float *f;
8199                         gboolean use_aotconst = FALSE;
8200
8201 #ifdef TARGET_POWERPC
8202                         /* FIXME: Clean this up */
8203                         if (cfg->compile_aot)
8204                                 use_aotconst = TRUE;
8205 #endif
8206
8207                         /* FIXME: we should really allocate this only late in the compilation process */
8208                         f = mono_domain_alloc (cfg->domain, sizeof (float));
8209                         CHECK_OPSIZE (5);
8210                         CHECK_STACK_OVF (1);
8211
8212                         if (use_aotconst) {
8213                                 MonoInst *cons;
8214                                 int dreg;
8215
8216                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8217
8218                                 dreg = alloc_freg (cfg);
8219                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8220                                 ins->type = STACK_R8;
8221                         } else {
8222                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8223                                 ins->type = STACK_R8;
8224                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8225                                 ins->inst_p0 = f;
8226                                 MONO_ADD_INS (bblock, ins);
8227                         }
8228                         ++ip;
8229                         readr4 (ip, f);
8230                         ip += 4;
8231                         *sp++ = ins;                    
8232                         break;
8233                 }
8234                 case CEE_LDC_R8: {
8235                         double *d;
8236                         gboolean use_aotconst = FALSE;
8237
8238 #ifdef TARGET_POWERPC
8239                         /* FIXME: Clean this up */
8240                         if (cfg->compile_aot)
8241                                 use_aotconst = TRUE;
8242 #endif
8243
8244                         /* FIXME: we should really allocate this only late in the compilation process */
8245                         d = mono_domain_alloc (cfg->domain, sizeof (double));
8246                         CHECK_OPSIZE (9);
8247                         CHECK_STACK_OVF (1);
8248
8249                         if (use_aotconst) {
8250                                 MonoInst *cons;
8251                                 int dreg;
8252
8253                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8254
8255                                 dreg = alloc_freg (cfg);
8256                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8257                                 ins->type = STACK_R8;
8258                         } else {
8259                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8260                                 ins->type = STACK_R8;
8261                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8262                                 ins->inst_p0 = d;
8263                                 MONO_ADD_INS (bblock, ins);
8264                         }
8265                         ++ip;
8266                         readr8 (ip, d);
8267                         ip += 8;
8268                         *sp++ = ins;
8269                         break;
8270                 }
8271                 case CEE_DUP: {
8272                         MonoInst *temp, *store;
8273                         CHECK_STACK (1);
8274                         CHECK_STACK_OVF (1);
8275                         sp--;
8276                         ins = *sp;
8277
8278                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8279                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8280
8281                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8282                         *sp++ = ins;
8283
8284                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8285                         *sp++ = ins;
8286
8287                         ++ip;
8288                         inline_costs += 2;
8289                         break;
8290                 }
8291                 case CEE_POP:
8292                         CHECK_STACK (1);
8293                         ip++;
8294                         --sp;
8295
8296 #ifdef TARGET_X86
8297                         if (sp [0]->type == STACK_R8)
8298                                 /* we need to pop the value from the x86 FP stack */
8299                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8300 #endif
8301                         break;
8302                 case CEE_JMP: {
8303                         MonoCallInst *call;
8304
8305                         INLINE_FAILURE ("jmp");
8306                         GSHAREDVT_FAILURE (*ip);
8307
8308                         CHECK_OPSIZE (5);
8309                         if (stack_start != sp)
8310                                 UNVERIFIED;
8311                         token = read32 (ip + 1);
8312                         /* FIXME: check the signature matches */
8313                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8314
8315                         if (!cmethod || mono_loader_get_last_error ())
8316                                 LOAD_ERROR;
8317  
8318                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
8319                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8320
8321                         if (mono_security_cas_enabled ())
8322                                 CHECK_CFG_EXCEPTION;
8323
8324                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8325
8326                         if (ARCH_HAVE_OP_TAIL_CALL) {
8327                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
8328                                 int i, n;
8329
8330                                 /* Handle tail calls similarly to calls */
8331                                 n = fsig->param_count + fsig->hasthis;
8332
8333                                 DISABLE_AOT (cfg);
8334
8335                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8336                                 call->method = cmethod;
8337                                 call->tail_call = TRUE;
8338                                 call->signature = mono_method_signature (cmethod);
8339                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8340                                 call->inst.inst_p0 = cmethod;
8341                                 for (i = 0; i < n; ++i)
8342                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8343
8344                                 mono_arch_emit_call (cfg, call);
8345                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8346                                 MONO_ADD_INS (bblock, (MonoInst*)call);
8347                         } else {
8348                                 for (i = 0; i < num_args; ++i)
8349                                         /* Prevent arguments from being optimized away */
8350                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8351
8352                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8353                                 ins = (MonoInst*)call;
8354                                 ins->inst_p0 = cmethod;
8355                                 MONO_ADD_INS (bblock, ins);
8356                         }
8357
8358                         ip += 5;
8359                         start_new_bblock = 1;
8360                         break;
8361                 }
8362                 case CEE_CALLI:
8363                 case CEE_CALL:
8364                 case CEE_CALLVIRT: {
8365                         MonoInst *addr = NULL;
8366                         MonoMethodSignature *fsig = NULL;
8367                         int array_rank = 0;
8368                         int virtual = *ip == CEE_CALLVIRT;
8369                         int calli = *ip == CEE_CALLI;
8370                         gboolean pass_imt_from_rgctx = FALSE;
8371                         MonoInst *imt_arg = NULL;
8372                         MonoInst *keep_this_alive = NULL;
8373                         gboolean pass_vtable = FALSE;
8374                         gboolean pass_mrgctx = FALSE;
8375                         MonoInst *vtable_arg = NULL;
8376                         gboolean check_this = FALSE;
8377                         gboolean supported_tail_call = FALSE;
8378                         gboolean tail_call = FALSE;
8379                         gboolean need_seq_point = FALSE;
8380                         guint32 call_opcode = *ip;
8381                         gboolean emit_widen = TRUE;
8382                         gboolean push_res = TRUE;
8383                         gboolean skip_ret = FALSE;
8384                         gboolean delegate_invoke = FALSE;
8385
8386                         CHECK_OPSIZE (5);
8387                         token = read32 (ip + 1);
8388
8389                         ins = NULL;
8390
8391                         if (calli) {
8392                                 //GSHAREDVT_FAILURE (*ip);
8393                                 cmethod = NULL;
8394                                 CHECK_STACK (1);
8395                                 --sp;
8396                                 addr = *sp;
8397                                 fsig = mini_get_signature (method, token, generic_context);
8398                                 n = fsig->param_count + fsig->hasthis;
8399
8400                                 if (method->dynamic && fsig->pinvoke) {
8401                                         MonoInst *args [3];
8402
8403                                         /*
8404                                          * This is a call through a function pointer using a pinvoke
8405                                          * signature. Have to create a wrapper and call that instead.
8406                                          * FIXME: This is very slow, need to create a wrapper at JIT time
8407                                          * instead based on the signature.
8408                                          */
8409                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8410                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
8411                                         args [2] = addr;
8412                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8413                                 }
8414                         } else {
8415                                 MonoMethod *cil_method;
8416
8417                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8418                                 cil_method = cmethod;
8419                                 
8420                                 if (constrained_call) {
8421                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8422                                                 if (cfg->verbose_level > 2)
8423                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8424                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
8425                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
8426                                                           cfg->generic_sharing_context)) {
8427                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context, &cfg->error);
8428                                                         CHECK_CFG_ERROR;
8429                                                 }
8430                                         } else {
8431                                                 if (cfg->verbose_level > 2)
8432                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
8433
8434                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
8435                                                         /* 
8436                                                          * This is needed since get_method_constrained can't find 
8437                                                          * the method in klass representing a type var.
8438                                                          * The type var is guaranteed to be a reference type in this
8439                                                          * case.
8440                                                          */
8441                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
8442                                                                 g_assert (!cmethod->klass->valuetype);
8443                                                 } else {
8444                                                         cmethod = mono_get_method_constrained_checked (image, token, constrained_call, generic_context, &cil_method, &cfg->error);
8445                                                         CHECK_CFG_ERROR;
8446                                                 }
8447                                         }
8448                                 }
8449                                         
8450                                 if (!cmethod || mono_loader_get_last_error ())
8451                                         LOAD_ERROR;
8452                                 if (!dont_verify && !cfg->skip_visibility) {
8453                                         MonoMethod *target_method = cil_method;
8454                                         if (method->is_inflated) {
8455                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8456                                         }
8457                                         if (!mono_method_can_access_method (method_definition, target_method) &&
8458                                                 !mono_method_can_access_method (method, cil_method))
8459                                                 METHOD_ACCESS_FAILURE (method, cil_method);
8460                                 }
8461
8462                                 if (mono_security_core_clr_enabled ())
8463                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
8464
8465                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8466                                         /* MS.NET seems to silently convert this to a callvirt */
8467                                         virtual = 1;
8468
8469                                 {
8470                                         /*
8471                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8472                                          * converts to a callvirt.
8473                                          *
8474                                          * tests/bug-515884.il is an example of this behavior
8475                                          */
8476                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8477                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8478                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8479                                                 virtual = 1;
8480                                 }
8481
8482                                 if (!cmethod->klass->inited)
8483                                         if (!mono_class_init (cmethod->klass))
8484                                                 TYPE_LOAD_ERROR (cmethod->klass);
8485
8486                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8487                                     mini_class_is_system_array (cmethod->klass)) {
8488                                         array_rank = cmethod->klass->rank;
8489                                         fsig = mono_method_signature (cmethod);
8490                                 } else {
8491                                         fsig = mono_method_signature (cmethod);
8492
8493                                         if (!fsig)
8494                                                 LOAD_ERROR;
8495
8496                                         if (fsig->pinvoke) {
8497                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
8498                                                         check_for_pending_exc, cfg->compile_aot);
8499                                                 fsig = mono_method_signature (wrapper);
8500                                         } else if (constrained_call) {
8501                                                 fsig = mono_method_signature (cmethod);
8502                                         } else {
8503                                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8504                                                 CHECK_CFG_ERROR;
8505                                         }
8506                                 }
8507
8508                                 mono_save_token_info (cfg, image, token, cil_method);
8509
8510                                 if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
8511                                         need_seq_point = TRUE;
8512
8513                                 n = fsig->param_count + fsig->hasthis;
8514
8515                                 /* Don't support calls made using type arguments for now */
8516                                 /*
8517                                 if (cfg->gsharedvt) {
8518                                         if (mini_is_gsharedvt_signature (cfg, fsig))
8519                                                 GSHAREDVT_FAILURE (*ip);
8520                                 }
8521                                 */
8522
8523                                 if (mono_security_cas_enabled ()) {
8524                                         if (check_linkdemand (cfg, method, cmethod))
8525                                                 INLINE_FAILURE ("linkdemand");
8526                                         CHECK_CFG_EXCEPTION;
8527                                 }
8528
8529                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
8530                                         g_assert_not_reached ();
8531                         }
8532
8533                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
8534                                 UNVERIFIED;
8535
8536                         if (!cfg->generic_sharing_context && cmethod)
8537                                 g_assert (!mono_method_check_context_used (cmethod));
8538
8539                         CHECK_STACK (n);
8540
8541                         //g_assert (!virtual || fsig->hasthis);
8542
8543                         sp -= n;
8544
8545                         if (constrained_call) {
8546                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
8547                                         /*
8548                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
8549                                          */
8550                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
8551                                                 /* The 'Own method' case below */
8552                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
8553                                                 /* 'The type parameter is instantiated as a reference type' case below. */
8554                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
8555                                                            (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)) &&
8556                                                            (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]))))) {
8557                                                 MonoInst *args [16];
8558
8559                                                 /*
8560                                                  * This case handles calls to
8561                                                  * - object:ToString()/Equals()/GetHashCode(),
8562                                                  * - System.IComparable<T>:CompareTo()
8563                                                  * - System.IEquatable<T>:Equals ()
8564                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
8565                                                  */
8566
8567                                                 args [0] = sp [0];
8568                                                 if (mono_method_check_context_used (cmethod))
8569                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
8570                                                 else
8571                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
8572                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
8573
8574                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
8575                                                 if (fsig->hasthis && fsig->param_count) {
8576                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
8577                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
8578                                                         ins->dreg = alloc_preg (cfg);
8579                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
8580                                                         MONO_ADD_INS (cfg->cbb, ins);
8581                                                         args [4] = ins;
8582
8583                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
8584                                                                 int addr_reg;
8585
8586                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
8587
8588                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
8589                                                                 addr_reg = ins->dreg;
8590                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
8591                                                         } else {
8592                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
8593                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
8594                                                         }
8595                                                 } else {
8596                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
8597                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
8598                                                 }
8599                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
8600                                                 emit_widen = FALSE;
8601
8602                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
8603                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
8604                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
8605                                                         MonoInst *add;
8606
8607                                                         /* Unbox */
8608                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
8609                                                         MONO_ADD_INS (cfg->cbb, add);
8610                                                         /* Load value */
8611                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
8612                                                         MONO_ADD_INS (cfg->cbb, ins);
8613                                                         /* ins represents the call result */
8614                                                 }
8615
8616                                                 goto call_end;
8617                                         } else {
8618                                                 GSHAREDVT_FAILURE (*ip);
8619                                         }
8620                                 }
8621                                 /*
8622                                  * We have the `constrained.' prefix opcode.
8623                                  */
8624                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
8625                                         /*
8626                                          * The type parameter is instantiated as a valuetype,
8627                                          * but that type doesn't override the method we're
8628                                          * calling, so we need to box `this'.
8629                                          */
8630                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8631                                         ins->klass = constrained_call;
8632                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8633                                         CHECK_CFG_EXCEPTION;
8634                                 } else if (!constrained_call->valuetype) {
8635                                         int dreg = alloc_ireg_ref (cfg);
8636
8637                                         /*
8638                                          * The type parameter is instantiated as a reference
8639                                          * type.  We have a managed pointer on the stack, so
8640                                          * we need to dereference it here.
8641                                          */
8642                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
8643                                         ins->type = STACK_OBJ;
8644                                         sp [0] = ins;
8645                                 } else {
8646                                         if (cmethod->klass->valuetype) {
8647                                                 /* Own method */
8648                                         } else {
8649                                                 /* Interface method */
8650                                                 int ioffset, slot;
8651
8652                                                 mono_class_setup_vtable (constrained_call);
8653                                                 CHECK_TYPELOAD (constrained_call);
8654                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
8655                                                 if (ioffset == -1)
8656                                                         TYPE_LOAD_ERROR (constrained_call);
8657                                                 slot = mono_method_get_vtable_slot (cmethod);
8658                                                 if (slot == -1)
8659                                                         TYPE_LOAD_ERROR (cmethod->klass);
8660                                                 cmethod = constrained_call->vtable [ioffset + slot];
8661
8662                                                 if (cmethod->klass == mono_defaults.enum_class) {
8663                                                         /* Enum implements some interfaces, so treat this as the first case */
8664                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
8665                                                         ins->klass = constrained_call;
8666                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
8667                                                         CHECK_CFG_EXCEPTION;
8668                                                 }
8669                                         }
8670                                         virtual = 0;
8671                                 }
8672                                 constrained_call = NULL;
8673                         }
8674
8675                         if (!calli && check_call_signature (cfg, fsig, sp))
8676                                 UNVERIFIED;
8677
8678 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
8679                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
8680                                 delegate_invoke = TRUE;
8681 #endif
8682
8683                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
8684                                 bblock = cfg->cbb;
8685                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8686                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8687                                         emit_widen = FALSE;
8688                                 }
8689
8690                                 goto call_end;
8691                         }
8692
8693                         /* 
8694                          * If the callee is a shared method, then its static cctor
8695                          * might not get called after the call was patched.
8696                          */
8697                         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)) {
8698                                 emit_generic_class_init (cfg, cmethod->klass);
8699                                 CHECK_TYPELOAD (cmethod->klass);
8700                         }
8701
8702                         if (cmethod)
8703                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
8704
8705                         if (cfg->generic_sharing_context && cmethod) {
8706                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
8707
8708                                 context_used = mini_method_check_context_used (cfg, cmethod);
8709
8710                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8711                                         /* Generic method interface
8712                                            calls are resolved via a
8713                                            helper function and don't
8714                                            need an imt. */
8715                                         if (!cmethod_context || !cmethod_context->method_inst)
8716                                                 pass_imt_from_rgctx = TRUE;
8717                                 }
8718
8719                                 /*
8720                                  * If a shared method calls another
8721                                  * shared method then the caller must
8722                                  * have a generic sharing context
8723                                  * because the magic trampoline
8724                                  * requires it.  FIXME: We shouldn't
8725                                  * have to force the vtable/mrgctx
8726                                  * variable here.  Instead there
8727                                  * should be a flag in the cfg to
8728                                  * request a generic sharing context.
8729                                  */
8730                                 if (context_used &&
8731                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
8732                                         mono_get_vtable_var (cfg);
8733                         }
8734
8735                         if (pass_vtable) {
8736                                 if (context_used) {
8737                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
8738                                 } else {
8739                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
8740
8741                                         CHECK_TYPELOAD (cmethod->klass);
8742                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
8743                                 }
8744                         }
8745
8746                         if (pass_mrgctx) {
8747                                 g_assert (!vtable_arg);
8748
8749                                 if (!cfg->compile_aot) {
8750                                         /* 
8751                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
8752                                          * for type load errors before.
8753                                          */
8754                                         mono_class_setup_vtable (cmethod->klass);
8755                                         CHECK_TYPELOAD (cmethod->klass);
8756                                 }
8757
8758                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
8759
8760                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
8761                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
8762                                          MONO_METHOD_IS_FINAL (cmethod)) &&
8763                                         !mono_class_is_marshalbyref (cmethod->klass)) {
8764                                         if (virtual)
8765                                                 check_this = TRUE;
8766                                         virtual = 0;
8767                                 }
8768                         }
8769
8770                         if (pass_imt_from_rgctx) {
8771                                 g_assert (!pass_vtable);
8772                                 g_assert (cmethod);
8773
8774                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8775                                         cmethod, MONO_RGCTX_INFO_METHOD);
8776                         }
8777
8778                         if (check_this)
8779                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8780
8781                         /* Calling virtual generic methods */
8782                         if (cmethod && virtual && 
8783                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
8784                             !(MONO_METHOD_IS_FINAL (cmethod) && 
8785                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
8786                             fsig->generic_param_count && 
8787                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
8788                                 MonoInst *this_temp, *this_arg_temp, *store;
8789                                 MonoInst *iargs [4];
8790                                 gboolean use_imt = FALSE;
8791
8792                                 g_assert (fsig->is_inflated);
8793
8794                                 /* Prevent inlining of methods that contain indirect calls */
8795                                 INLINE_FAILURE ("virtual generic call");
8796
8797                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
8798                                         GSHAREDVT_FAILURE (*ip);
8799
8800 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
8801                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
8802                                         use_imt = TRUE;
8803 #endif
8804
8805                                 if (use_imt) {
8806                                         g_assert (!imt_arg);
8807                                         if (!context_used)
8808                                                 g_assert (cmethod->is_inflated);
8809                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
8810                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
8811                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
8812                                 } else {
8813                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
8814                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
8815                                         MONO_ADD_INS (bblock, store);
8816
8817                                         /* FIXME: This should be a managed pointer */
8818                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8819
8820                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
8821                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
8822                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
8823                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
8824                                         addr = mono_emit_jit_icall (cfg,
8825                                                                                                 mono_helper_compile_generic_method, iargs);
8826
8827                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
8828
8829                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8830                                 }
8831
8832                                 goto call_end;
8833                         }
8834
8835                         /*
8836                          * Implement a workaround for the inherent races involved in locking:
8837                          * Monitor.Enter ()
8838                          * try {
8839                          * } finally {
8840                          *    Monitor.Exit ()
8841                          * }
8842                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
8843                          * try block, the Exit () won't be executed, see:
8844                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
8845                          * To work around this, we extend such try blocks to include the last x bytes
8846                          * of the Monitor.Enter () call.
8847                          */
8848                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8849                                 MonoBasicBlock *tbb;
8850
8851                                 GET_BBLOCK (cfg, tbb, ip + 5);
8852                                 /* 
8853                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
8854                                  * from Monitor.Enter like ArgumentNullException.
8855                                  */
8856                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8857                                         /* Mark this bblock as needing to be extended */
8858                                         tbb->extend_try_block = TRUE;
8859                                 }
8860                         }
8861
8862                         /* Conversion to a JIT intrinsic */
8863                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
8864                                 bblock = cfg->cbb;
8865                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8866                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
8867                                         emit_widen = FALSE;
8868                                 }
8869                                 goto call_end;
8870                         }
8871
8872                         /* Inlining */
8873                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
8874                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
8875                             mono_method_check_inlining (cfg, cmethod)) {
8876                                 int costs;
8877                                 gboolean always = FALSE;
8878
8879                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
8880                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
8881                                         /* Prevent inlining of methods that call wrappers */
8882                                         INLINE_FAILURE ("wrapper call");
8883                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
8884                                         always = TRUE;
8885                                 }
8886
8887                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always, &bblock);
8888                                 if (costs) {
8889                                         cfg->real_offset += 5;
8890
8891                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8892                                                 /* *sp is already set by inline_method */
8893                                                 sp++;
8894                                                 push_res = FALSE;
8895                                         }
8896
8897                                         inline_costs += costs;
8898
8899                                         goto call_end;
8900                                 }
8901                         }
8902
8903                         /* Tail recursion elimination */
8904                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8905                                 gboolean has_vtargs = FALSE;
8906                                 int i;
8907
8908                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8909                                 INLINE_FAILURE ("tail call");
8910
8911                                 /* keep it simple */
8912                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8913                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8914                                                 has_vtargs = TRUE;
8915                                 }
8916
8917                                 if (!has_vtargs) {
8918                                         for (i = 0; i < n; ++i)
8919                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8920                                         MONO_INST_NEW (cfg, ins, OP_BR);
8921                                         MONO_ADD_INS (bblock, ins);
8922                                         tblock = start_bblock->out_bb [0];
8923                                         link_bblock (cfg, bblock, tblock);
8924                                         ins->inst_target_bb = tblock;
8925                                         start_new_bblock = 1;
8926
8927                                         /* skip the CEE_RET, too */
8928                                         if (ip_in_bb (cfg, bblock, ip + 5))
8929                                                 skip_ret = TRUE;
8930                                         push_res = FALSE;
8931                                         goto call_end;
8932                                 }
8933                         }
8934
8935                         inline_costs += 10 * num_calls++;
8936
8937                         /*
8938                          * Making generic calls out of gsharedvt methods.
8939                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8940                          * patching gshared method addresses into a gsharedvt method.
8941                          */
8942                         if (cmethod && cfg->gsharedvt && (mini_is_gsharedvt_signature (cfg, fsig) || cmethod->is_inflated || cmethod->klass->generic_class)) {
8943                                 MonoRgctxInfoType info_type;
8944
8945                                 if (virtual) {
8946                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8947                                                 //GSHAREDVT_FAILURE (*ip);
8948                                         // disable for possible remoting calls
8949                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8950                                                 GSHAREDVT_FAILURE (*ip);
8951                                         if (fsig->generic_param_count) {
8952                                                 /* virtual generic call */
8953                                                 g_assert (mono_use_imt);
8954                                                 g_assert (!imt_arg);
8955                                                 /* Same as the virtual generic case above */
8956                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8957                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8958                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8959                                                 vtable_arg = NULL;
8960                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
8961                                                 /* This can happen when we call a fully instantiated iface method */
8962                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8963                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8964                                                 vtable_arg = NULL;
8965                                         }
8966                                 }
8967
8968                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8969                                         /* test_0_multi_dim_arrays () in gshared.cs */
8970                                         GSHAREDVT_FAILURE (*ip);
8971
8972                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8973                                         keep_this_alive = sp [0];
8974
8975                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8976                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8977                                 else
8978                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8979                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8980
8981                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8982                                 goto call_end;
8983                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8984                                 /*
8985                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8986                                  */
8987                                 MonoInst *callee = addr;
8988
8989                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8990                                         /* Not tested */
8991                                         GSHAREDVT_FAILURE (*ip);
8992
8993                                 addr = emit_get_rgctx_sig (cfg, context_used,
8994                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8995                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8996                                 goto call_end;
8997                         }
8998
8999                         /* Generic sharing */
9000
9001                         /*
9002                          * Use this if the callee is gsharedvt sharable too, since
9003                          * at runtime we might find an instantiation so the call cannot
9004                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9005                          */
9006                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9007                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9008                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9009                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
9010                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9011                                 INLINE_FAILURE ("gshared");
9012
9013                                 g_assert (cfg->generic_sharing_context && cmethod);
9014                                 g_assert (!addr);
9015
9016                                 /*
9017                                  * We are compiling a call to a
9018                                  * generic method from shared code,
9019                                  * which means that we have to look up
9020                                  * the method in the rgctx and do an
9021                                  * indirect call.
9022                                  */
9023                                 if (fsig->hasthis)
9024                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9025
9026                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9027                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9028                                 goto call_end;
9029                         }
9030
9031                         /* Indirect calls */
9032                         if (addr) {
9033                                 if (call_opcode == CEE_CALL)
9034                                         g_assert (context_used);
9035                                 else if (call_opcode == CEE_CALLI)
9036                                         g_assert (!vtable_arg);
9037                                 else
9038                                         /* FIXME: what the hell is this??? */
9039                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
9040                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
9041
9042                                 /* Prevent inlining of methods with indirect calls */
9043                                 INLINE_FAILURE ("indirect call");
9044
9045                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
9046                                         int info_type;
9047                                         gpointer info_data;
9048
9049                                         /* 
9050                                          * Instead of emitting an indirect call, emit a direct call
9051                                          * with the contents of the aotconst as the patch info.
9052                                          */
9053                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
9054                                                 info_type = addr->inst_c1;
9055                                                 info_data = addr->inst_p0;
9056                                         } else {
9057                                                 info_type = addr->inst_right->inst_c1;
9058                                                 info_data = addr->inst_right->inst_left;
9059                                         }
9060                                         
9061                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
9062                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
9063                                                 NULLIFY_INS (addr);
9064                                                 goto call_end;
9065                                         }
9066                                 }
9067                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9068                                 goto call_end;
9069                         }
9070                                         
9071                         /* Array methods */
9072                         if (array_rank) {
9073                                 MonoInst *addr;
9074
9075                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9076                                         MonoInst *val = sp [fsig->param_count];
9077
9078                                         if (val->type == STACK_OBJ) {
9079                                                 MonoInst *iargs [2];
9080
9081                                                 iargs [0] = sp [0];
9082                                                 iargs [1] = val;
9083                                                 
9084                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9085                                         }
9086                                         
9087                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9088                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9089                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9090                                                 emit_write_barrier (cfg, addr, val);
9091                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9092                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9093
9094                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9095                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9096                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9097                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9098                                         CHECK_TYPELOAD (cmethod->klass);
9099                                         
9100                                         readonly = FALSE;
9101                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9102                                         ins = addr;
9103                                 } else {
9104                                         g_assert_not_reached ();
9105                                 }
9106
9107                                 emit_widen = FALSE;
9108                                 goto call_end;
9109                         }
9110
9111                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
9112                         if (ins)
9113                                 goto call_end;
9114
9115                         /* Tail prefix / tail call optimization */
9116
9117                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9118                         /* FIXME: runtime generic context pointer for jumps? */
9119                         /* FIXME: handle this for generic sharing eventually */
9120                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
9121                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9122                                 supported_tail_call = TRUE;
9123
9124                         if (supported_tail_call) {
9125                                 MonoCallInst *call;
9126
9127                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9128                                 INLINE_FAILURE ("tail call");
9129
9130                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9131
9132                                 if (ARCH_HAVE_OP_TAIL_CALL) {
9133                                         /* Handle tail calls similarly to normal calls */
9134                                         tail_call = TRUE;
9135                                 } else {
9136                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9137
9138                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9139                                         call->tail_call = TRUE;
9140                                         call->method = cmethod;
9141                                         call->signature = mono_method_signature (cmethod);
9142
9143                                         /*
9144                                          * We implement tail calls by storing the actual arguments into the 
9145                                          * argument variables, then emitting a CEE_JMP.
9146                                          */
9147                                         for (i = 0; i < n; ++i) {
9148                                                 /* Prevent argument from being register allocated */
9149                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9150                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9151                                         }
9152                                         ins = (MonoInst*)call;
9153                                         ins->inst_p0 = cmethod;
9154                                         ins->inst_p1 = arg_array [0];
9155                                         MONO_ADD_INS (bblock, ins);
9156                                         link_bblock (cfg, bblock, end_bblock);                  
9157                                         start_new_bblock = 1;
9158
9159                                         // FIXME: Eliminate unreachable epilogs
9160
9161                                         /*
9162                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9163                                          * only reachable from this call.
9164                                          */
9165                                         GET_BBLOCK (cfg, tblock, ip + 5);
9166                                         if (tblock == bblock || tblock->in_count == 0)
9167                                                 skip_ret = TRUE;
9168                                         push_res = FALSE;
9169
9170                                         goto call_end;
9171                                 }
9172                         }
9173
9174                         /* 
9175                          * Synchronized wrappers.
9176                          * Its hard to determine where to replace a method with its synchronized
9177                          * wrapper without causing an infinite recursion. The current solution is
9178                          * to add the synchronized wrapper in the trampolines, and to
9179                          * change the called method to a dummy wrapper, and resolve that wrapper
9180                          * to the real method in mono_jit_compile_method ().
9181                          */
9182                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9183                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9184                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9185                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9186                         }
9187
9188                         /* Common call */
9189                         INLINE_FAILURE ("call");
9190                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
9191                                                                                           imt_arg, vtable_arg);
9192
9193                         if (tail_call) {
9194                                 link_bblock (cfg, bblock, end_bblock);                  
9195                                 start_new_bblock = 1;
9196
9197                                 // FIXME: Eliminate unreachable epilogs
9198
9199                                 /*
9200                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9201                                  * only reachable from this call.
9202                                  */
9203                                 GET_BBLOCK (cfg, tblock, ip + 5);
9204                                 if (tblock == bblock || tblock->in_count == 0)
9205                                         skip_ret = TRUE;
9206                                 push_res = FALSE;
9207                         }
9208
9209                         call_end:
9210
9211                         /* End of call, INS should contain the result of the call, if any */
9212
9213                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9214                                 g_assert (ins);
9215                                 if (emit_widen)
9216                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9217                                 else
9218                                         *sp++ = ins;
9219                         }
9220
9221                         if (keep_this_alive) {
9222                                 MonoInst *dummy_use;
9223
9224                                 /* See mono_emit_method_call_full () */
9225                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9226                         }
9227
9228                         CHECK_CFG_EXCEPTION;
9229
9230                         ip += 5;
9231                         if (skip_ret) {
9232                                 g_assert (*ip == CEE_RET);
9233                                 ip += 1;
9234                         }
9235                         ins_flag = 0;
9236                         constrained_call = NULL;
9237                         if (need_seq_point)
9238                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9239                         break;
9240                 }
9241                 case CEE_RET:
9242                         if (cfg->method != method) {
9243                                 /* return from inlined method */
9244                                 /* 
9245                                  * If in_count == 0, that means the ret is unreachable due to
9246                                  * being preceeded by a throw. In that case, inline_method () will
9247                                  * handle setting the return value 
9248                                  * (test case: test_0_inline_throw ()).
9249                                  */
9250                                 if (return_var && cfg->cbb->in_count) {
9251                                         MonoType *ret_type = mono_method_signature (method)->ret;
9252
9253                                         MonoInst *store;
9254                                         CHECK_STACK (1);
9255                                         --sp;
9256
9257                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9258                                                 UNVERIFIED;
9259
9260                                         //g_assert (returnvar != -1);
9261                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9262                                         cfg->ret_var_set = TRUE;
9263                                 } 
9264                         } else {
9265                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9266
9267                                 if (cfg->lmf_var && cfg->cbb->in_count)
9268                                         emit_pop_lmf (cfg);
9269
9270                                 if (cfg->ret) {
9271                                         MonoType *ret_type = mini_replace_type (mono_method_signature (method)->ret);
9272
9273                                         if (seq_points && !sym_seq_points) {
9274                                                 /* 
9275                                                  * Place a seq point here too even through the IL stack is not
9276                                                  * empty, so a step over on
9277                                                  * call <FOO>
9278                                                  * ret
9279                                                  * will work correctly.
9280                                                  */
9281                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9282                                                 MONO_ADD_INS (cfg->cbb, ins);
9283                                         }
9284
9285                                         g_assert (!return_var);
9286                                         CHECK_STACK (1);
9287                                         --sp;
9288
9289                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9290                                                 UNVERIFIED;
9291
9292                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
9293                                                 MonoInst *ret_addr;
9294
9295                                                 if (!cfg->vret_addr) {
9296                                                         MonoInst *ins;
9297
9298                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
9299                                                 } else {
9300                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
9301
9302                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
9303                                                         ins->klass = mono_class_from_mono_type (ret_type);
9304                                                 }
9305                                         } else {
9306 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
9307                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
9308                                                         MonoInst *iargs [1];
9309                                                         MonoInst *conv;
9310
9311                                                         iargs [0] = *sp;
9312                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
9313                                                         mono_arch_emit_setret (cfg, method, conv);
9314                                                 } else {
9315                                                         mono_arch_emit_setret (cfg, method, *sp);
9316                                                 }
9317 #else
9318                                                 mono_arch_emit_setret (cfg, method, *sp);
9319 #endif
9320                                         }
9321                                 }
9322                         }
9323                         if (sp != stack_start)
9324                                 UNVERIFIED;
9325                         MONO_INST_NEW (cfg, ins, OP_BR);
9326                         ip++;
9327                         ins->inst_target_bb = end_bblock;
9328                         MONO_ADD_INS (bblock, ins);
9329                         link_bblock (cfg, bblock, end_bblock);
9330                         start_new_bblock = 1;
9331                         break;
9332                 case CEE_BR_S:
9333                         CHECK_OPSIZE (2);
9334                         MONO_INST_NEW (cfg, ins, OP_BR);
9335                         ip++;
9336                         target = ip + 1 + (signed char)(*ip);
9337                         ++ip;
9338                         GET_BBLOCK (cfg, tblock, target);
9339                         link_bblock (cfg, bblock, tblock);
9340                         ins->inst_target_bb = tblock;
9341                         if (sp != stack_start) {
9342                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9343                                 sp = stack_start;
9344                                 CHECK_UNVERIFIABLE (cfg);
9345                         }
9346                         MONO_ADD_INS (bblock, ins);
9347                         start_new_bblock = 1;
9348                         inline_costs += BRANCH_COST;
9349                         break;
9350                 case CEE_BEQ_S:
9351                 case CEE_BGE_S:
9352                 case CEE_BGT_S:
9353                 case CEE_BLE_S:
9354                 case CEE_BLT_S:
9355                 case CEE_BNE_UN_S:
9356                 case CEE_BGE_UN_S:
9357                 case CEE_BGT_UN_S:
9358                 case CEE_BLE_UN_S:
9359                 case CEE_BLT_UN_S:
9360                         CHECK_OPSIZE (2);
9361                         CHECK_STACK (2);
9362                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9363                         ip++;
9364                         target = ip + 1 + *(signed char*)ip;
9365                         ip++;
9366
9367                         ADD_BINCOND (NULL);
9368
9369                         sp = stack_start;
9370                         inline_costs += BRANCH_COST;
9371                         break;
9372                 case CEE_BR:
9373                         CHECK_OPSIZE (5);
9374                         MONO_INST_NEW (cfg, ins, OP_BR);
9375                         ip++;
9376
9377                         target = ip + 4 + (gint32)read32(ip);
9378                         ip += 4;
9379                         GET_BBLOCK (cfg, tblock, target);
9380                         link_bblock (cfg, bblock, tblock);
9381                         ins->inst_target_bb = tblock;
9382                         if (sp != stack_start) {
9383                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9384                                 sp = stack_start;
9385                                 CHECK_UNVERIFIABLE (cfg);
9386                         }
9387
9388                         MONO_ADD_INS (bblock, ins);
9389
9390                         start_new_bblock = 1;
9391                         inline_costs += BRANCH_COST;
9392                         break;
9393                 case CEE_BRFALSE_S:
9394                 case CEE_BRTRUE_S:
9395                 case CEE_BRFALSE:
9396                 case CEE_BRTRUE: {
9397                         MonoInst *cmp;
9398                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9399                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9400                         guint32 opsize = is_short ? 1 : 4;
9401
9402                         CHECK_OPSIZE (opsize);
9403                         CHECK_STACK (1);
9404                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9405                                 UNVERIFIED;
9406                         ip ++;
9407                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9408                         ip += opsize;
9409
9410                         sp--;
9411
9412                         GET_BBLOCK (cfg, tblock, target);
9413                         link_bblock (cfg, bblock, tblock);
9414                         GET_BBLOCK (cfg, tblock, ip);
9415                         link_bblock (cfg, bblock, tblock);
9416
9417                         if (sp != stack_start) {
9418                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9419                                 CHECK_UNVERIFIABLE (cfg);
9420                         }
9421
9422                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9423                         cmp->sreg1 = sp [0]->dreg;
9424                         type_from_op (cmp, sp [0], NULL);
9425                         CHECK_TYPE (cmp);
9426
9427 #if SIZEOF_REGISTER == 4
9428                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9429                                 /* Convert it to OP_LCOMPARE */
9430                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9431                                 ins->type = STACK_I8;
9432                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9433                                 ins->inst_l = 0;
9434                                 MONO_ADD_INS (bblock, ins);
9435                                 cmp->opcode = OP_LCOMPARE;
9436                                 cmp->sreg2 = ins->dreg;
9437                         }
9438 #endif
9439                         MONO_ADD_INS (bblock, cmp);
9440
9441                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9442                         type_from_op (ins, sp [0], NULL);
9443                         MONO_ADD_INS (bblock, ins);
9444                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9445                         GET_BBLOCK (cfg, tblock, target);
9446                         ins->inst_true_bb = tblock;
9447                         GET_BBLOCK (cfg, tblock, ip);
9448                         ins->inst_false_bb = tblock;
9449                         start_new_bblock = 2;
9450
9451                         sp = stack_start;
9452                         inline_costs += BRANCH_COST;
9453                         break;
9454                 }
9455                 case CEE_BEQ:
9456                 case CEE_BGE:
9457                 case CEE_BGT:
9458                 case CEE_BLE:
9459                 case CEE_BLT:
9460                 case CEE_BNE_UN:
9461                 case CEE_BGE_UN:
9462                 case CEE_BGT_UN:
9463                 case CEE_BLE_UN:
9464                 case CEE_BLT_UN:
9465                         CHECK_OPSIZE (5);
9466                         CHECK_STACK (2);
9467                         MONO_INST_NEW (cfg, ins, *ip);
9468                         ip++;
9469                         target = ip + 4 + (gint32)read32(ip);
9470                         ip += 4;
9471
9472                         ADD_BINCOND (NULL);
9473
9474                         sp = stack_start;
9475                         inline_costs += BRANCH_COST;
9476                         break;
9477                 case CEE_SWITCH: {
9478                         MonoInst *src1;
9479                         MonoBasicBlock **targets;
9480                         MonoBasicBlock *default_bblock;
9481                         MonoJumpInfoBBTable *table;
9482                         int offset_reg = alloc_preg (cfg);
9483                         int target_reg = alloc_preg (cfg);
9484                         int table_reg = alloc_preg (cfg);
9485                         int sum_reg = alloc_preg (cfg);
9486                         gboolean use_op_switch;
9487
9488                         CHECK_OPSIZE (5);
9489                         CHECK_STACK (1);
9490                         n = read32 (ip + 1);
9491                         --sp;
9492                         src1 = sp [0];
9493                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9494                                 UNVERIFIED;
9495
9496                         ip += 5;
9497                         CHECK_OPSIZE (n * sizeof (guint32));
9498                         target = ip + n * sizeof (guint32);
9499
9500                         GET_BBLOCK (cfg, default_bblock, target);
9501                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9502
9503                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9504                         for (i = 0; i < n; ++i) {
9505                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9506                                 targets [i] = tblock;
9507                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9508                                 ip += 4;
9509                         }
9510
9511                         if (sp != stack_start) {
9512                                 /* 
9513                                  * Link the current bb with the targets as well, so handle_stack_args
9514                                  * will set their in_stack correctly.
9515                                  */
9516                                 link_bblock (cfg, bblock, default_bblock);
9517                                 for (i = 0; i < n; ++i)
9518                                         link_bblock (cfg, bblock, targets [i]);
9519
9520                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9521                                 sp = stack_start;
9522                                 CHECK_UNVERIFIABLE (cfg);
9523                         }
9524
9525                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
9526                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
9527                         bblock = cfg->cbb;
9528
9529                         for (i = 0; i < n; ++i)
9530                                 link_bblock (cfg, bblock, targets [i]);
9531
9532                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
9533                         table->table = targets;
9534                         table->table_size = n;
9535
9536                         use_op_switch = FALSE;
9537 #ifdef TARGET_ARM
9538                         /* ARM implements SWITCH statements differently */
9539                         /* FIXME: Make it use the generic implementation */
9540                         if (!cfg->compile_aot)
9541                                 use_op_switch = TRUE;
9542 #endif
9543
9544                         if (COMPILE_LLVM (cfg))
9545                                 use_op_switch = TRUE;
9546
9547                         cfg->cbb->has_jump_table = 1;
9548
9549                         if (use_op_switch) {
9550                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
9551                                 ins->sreg1 = src1->dreg;
9552                                 ins->inst_p0 = table;
9553                                 ins->inst_many_bb = targets;
9554                                 ins->klass = GUINT_TO_POINTER (n);
9555                                 MONO_ADD_INS (cfg->cbb, ins);
9556                         } else {
9557                                 if (sizeof (gpointer) == 8)
9558                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
9559                                 else
9560                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
9561
9562 #if SIZEOF_REGISTER == 8
9563                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
9564                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
9565 #endif
9566
9567                                 if (cfg->compile_aot) {
9568                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
9569                                 } else {
9570                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
9571                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
9572                                         ins->inst_p0 = table;
9573                                         ins->dreg = table_reg;
9574                                         MONO_ADD_INS (cfg->cbb, ins);
9575                                 }
9576
9577                                 /* FIXME: Use load_memindex */
9578                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
9579                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
9580                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
9581                         }
9582                         start_new_bblock = 1;
9583                         inline_costs += (BRANCH_COST * 2);
9584                         break;
9585                 }
9586                 case CEE_LDIND_I1:
9587                 case CEE_LDIND_U1:
9588                 case CEE_LDIND_I2:
9589                 case CEE_LDIND_U2:
9590                 case CEE_LDIND_I4:
9591                 case CEE_LDIND_U4:
9592                 case CEE_LDIND_I8:
9593                 case CEE_LDIND_I:
9594                 case CEE_LDIND_R4:
9595                 case CEE_LDIND_R8:
9596                 case CEE_LDIND_REF:
9597                         CHECK_STACK (1);
9598                         --sp;
9599
9600                         switch (*ip) {
9601                         case CEE_LDIND_R4:
9602                         case CEE_LDIND_R8:
9603                                 dreg = alloc_freg (cfg);
9604                                 break;
9605                         case CEE_LDIND_I8:
9606                                 dreg = alloc_lreg (cfg);
9607                                 break;
9608                         case CEE_LDIND_REF:
9609                                 dreg = alloc_ireg_ref (cfg);
9610                                 break;
9611                         default:
9612                                 dreg = alloc_preg (cfg);
9613                         }
9614
9615                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
9616                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
9617                         ins->flags |= ins_flag;
9618                         MONO_ADD_INS (bblock, ins);
9619                         *sp++ = ins;
9620                         if (ins_flag & MONO_INST_VOLATILE) {
9621                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9622                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9623                         }
9624                         ins_flag = 0;
9625                         ++ip;
9626                         break;
9627                 case CEE_STIND_REF:
9628                 case CEE_STIND_I1:
9629                 case CEE_STIND_I2:
9630                 case CEE_STIND_I4:
9631                 case CEE_STIND_I8:
9632                 case CEE_STIND_R4:
9633                 case CEE_STIND_R8:
9634                 case CEE_STIND_I:
9635                         CHECK_STACK (2);
9636                         sp -= 2;
9637
9638                         if (ins_flag & MONO_INST_VOLATILE) {
9639                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
9640                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
9641                         }
9642
9643                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
9644                         ins->flags |= ins_flag;
9645                         ins_flag = 0;
9646
9647                         MONO_ADD_INS (bblock, ins);
9648
9649                         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)))
9650                                 emit_write_barrier (cfg, sp [0], sp [1]);
9651
9652                         inline_costs += 1;
9653                         ++ip;
9654                         break;
9655
9656                 case CEE_MUL:
9657                         CHECK_STACK (2);
9658
9659                         MONO_INST_NEW (cfg, ins, (*ip));
9660                         sp -= 2;
9661                         ins->sreg1 = sp [0]->dreg;
9662                         ins->sreg2 = sp [1]->dreg;
9663                         type_from_op (ins, sp [0], sp [1]);
9664                         CHECK_TYPE (ins);
9665                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9666
9667                         /* Use the immediate opcodes if possible */
9668                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
9669                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9670                                 if (imm_opcode != -1) {
9671                                         ins->opcode = imm_opcode;
9672                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
9673                                         ins->sreg2 = -1;
9674
9675                                         NULLIFY_INS (sp [1]);
9676                                 }
9677                         }
9678
9679                         MONO_ADD_INS ((cfg)->cbb, (ins));
9680
9681                         *sp++ = mono_decompose_opcode (cfg, ins);
9682                         ip++;
9683                         break;
9684                 case CEE_ADD:
9685                 case CEE_SUB:
9686                 case CEE_DIV:
9687                 case CEE_DIV_UN:
9688                 case CEE_REM:
9689                 case CEE_REM_UN:
9690                 case CEE_AND:
9691                 case CEE_OR:
9692                 case CEE_XOR:
9693                 case CEE_SHL:
9694                 case CEE_SHR:
9695                 case CEE_SHR_UN:
9696                         CHECK_STACK (2);
9697
9698                         MONO_INST_NEW (cfg, ins, (*ip));
9699                         sp -= 2;
9700                         ins->sreg1 = sp [0]->dreg;
9701                         ins->sreg2 = sp [1]->dreg;
9702                         type_from_op (ins, sp [0], sp [1]);
9703                         CHECK_TYPE (ins);
9704                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
9705                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
9706
9707                         /* FIXME: Pass opcode to is_inst_imm */
9708
9709                         /* Use the immediate opcodes if possible */
9710                         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)) {
9711                                 int imm_opcode;
9712
9713                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
9714 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
9715                                 /* Keep emulated opcodes which are optimized away later */
9716                                 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) {
9717                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
9718                                 }
9719 #endif
9720                                 if (imm_opcode != -1) {
9721                                         ins->opcode = imm_opcode;
9722                                         if (sp [1]->opcode == OP_I8CONST) {
9723 #if SIZEOF_REGISTER == 8
9724                                                 ins->inst_imm = sp [1]->inst_l;
9725 #else
9726                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
9727                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
9728 #endif
9729                                         }
9730                                         else
9731                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
9732                                         ins->sreg2 = -1;
9733
9734                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
9735                                         if (sp [1]->next == NULL)
9736                                                 NULLIFY_INS (sp [1]);
9737                                 }
9738                         }
9739                         MONO_ADD_INS ((cfg)->cbb, (ins));
9740
9741                         *sp++ = mono_decompose_opcode (cfg, ins);
9742                         ip++;
9743                         break;
9744                 case CEE_NEG:
9745                 case CEE_NOT:
9746                 case CEE_CONV_I1:
9747                 case CEE_CONV_I2:
9748                 case CEE_CONV_I4:
9749                 case CEE_CONV_R4:
9750                 case CEE_CONV_R8:
9751                 case CEE_CONV_U4:
9752                 case CEE_CONV_I8:
9753                 case CEE_CONV_U8:
9754                 case CEE_CONV_OVF_I8:
9755                 case CEE_CONV_OVF_U8:
9756                 case CEE_CONV_R_UN:
9757                         CHECK_STACK (1);
9758
9759                         /* Special case this earlier so we have long constants in the IR */
9760                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
9761                                 int data = sp [-1]->inst_c0;
9762                                 sp [-1]->opcode = OP_I8CONST;
9763                                 sp [-1]->type = STACK_I8;
9764 #if SIZEOF_REGISTER == 8
9765                                 if ((*ip) == CEE_CONV_U8)
9766                                         sp [-1]->inst_c0 = (guint32)data;
9767                                 else
9768                                         sp [-1]->inst_c0 = data;
9769 #else
9770                                 sp [-1]->inst_ls_word = data;
9771                                 if ((*ip) == CEE_CONV_U8)
9772                                         sp [-1]->inst_ms_word = 0;
9773                                 else
9774                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
9775 #endif
9776                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
9777                         }
9778                         else {
9779                                 ADD_UNOP (*ip);
9780                         }
9781                         ip++;
9782                         break;
9783                 case CEE_CONV_OVF_I4:
9784                 case CEE_CONV_OVF_I1:
9785                 case CEE_CONV_OVF_I2:
9786                 case CEE_CONV_OVF_I:
9787                 case CEE_CONV_OVF_U:
9788                         CHECK_STACK (1);
9789
9790                         if (sp [-1]->type == STACK_R8) {
9791                                 ADD_UNOP (CEE_CONV_OVF_I8);
9792                                 ADD_UNOP (*ip);
9793                         } else {
9794                                 ADD_UNOP (*ip);
9795                         }
9796                         ip++;
9797                         break;
9798                 case CEE_CONV_OVF_U1:
9799                 case CEE_CONV_OVF_U2:
9800                 case CEE_CONV_OVF_U4:
9801                         CHECK_STACK (1);
9802
9803                         if (sp [-1]->type == STACK_R8) {
9804                                 ADD_UNOP (CEE_CONV_OVF_U8);
9805                                 ADD_UNOP (*ip);
9806                         } else {
9807                                 ADD_UNOP (*ip);
9808                         }
9809                         ip++;
9810                         break;
9811                 case CEE_CONV_OVF_I1_UN:
9812                 case CEE_CONV_OVF_I2_UN:
9813                 case CEE_CONV_OVF_I4_UN:
9814                 case CEE_CONV_OVF_I8_UN:
9815                 case CEE_CONV_OVF_U1_UN:
9816                 case CEE_CONV_OVF_U2_UN:
9817                 case CEE_CONV_OVF_U4_UN:
9818                 case CEE_CONV_OVF_U8_UN:
9819                 case CEE_CONV_OVF_I_UN:
9820                 case CEE_CONV_OVF_U_UN:
9821                 case CEE_CONV_U2:
9822                 case CEE_CONV_U1:
9823                 case CEE_CONV_I:
9824                 case CEE_CONV_U:
9825                         CHECK_STACK (1);
9826                         ADD_UNOP (*ip);
9827                         CHECK_CFG_EXCEPTION;
9828                         ip++;
9829                         break;
9830                 case CEE_ADD_OVF:
9831                 case CEE_ADD_OVF_UN:
9832                 case CEE_MUL_OVF:
9833                 case CEE_MUL_OVF_UN:
9834                 case CEE_SUB_OVF:
9835                 case CEE_SUB_OVF_UN:
9836                         CHECK_STACK (2);
9837                         ADD_BINOP (*ip);
9838                         ip++;
9839                         break;
9840                 case CEE_CPOBJ:
9841                         GSHAREDVT_FAILURE (*ip);
9842                         CHECK_OPSIZE (5);
9843                         CHECK_STACK (2);
9844                         token = read32 (ip + 1);
9845                         klass = mini_get_class (method, token, generic_context);
9846                         CHECK_TYPELOAD (klass);
9847                         sp -= 2;
9848                         if (generic_class_is_reference_type (cfg, klass)) {
9849                                 MonoInst *store, *load;
9850                                 int dreg = alloc_ireg_ref (cfg);
9851
9852                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
9853                                 load->flags |= ins_flag;
9854                                 MONO_ADD_INS (cfg->cbb, load);
9855
9856                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
9857                                 store->flags |= ins_flag;
9858                                 MONO_ADD_INS (cfg->cbb, store);
9859
9860                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
9861                                         emit_write_barrier (cfg, sp [0], sp [1]);
9862                         } else {
9863                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9864                         }
9865                         ins_flag = 0;
9866                         ip += 5;
9867                         break;
9868                 case CEE_LDOBJ: {
9869                         int loc_index = -1;
9870                         int stloc_len = 0;
9871
9872                         CHECK_OPSIZE (5);
9873                         CHECK_STACK (1);
9874                         --sp;
9875                         token = read32 (ip + 1);
9876                         klass = mini_get_class (method, token, generic_context);
9877                         CHECK_TYPELOAD (klass);
9878
9879                         /* Optimize the common ldobj+stloc combination */
9880                         switch (ip [5]) {
9881                         case CEE_STLOC_S:
9882                                 loc_index = ip [6];
9883                                 stloc_len = 2;
9884                                 break;
9885                         case CEE_STLOC_0:
9886                         case CEE_STLOC_1:
9887                         case CEE_STLOC_2:
9888                         case CEE_STLOC_3:
9889                                 loc_index = ip [5] - CEE_STLOC_0;
9890                                 stloc_len = 1;
9891                                 break;
9892                         default:
9893                                 break;
9894                         }
9895
9896                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
9897                                 CHECK_LOCAL (loc_index);
9898
9899                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9900                                 ins->dreg = cfg->locals [loc_index]->dreg;
9901                                 ins->flags |= ins_flag;
9902                                 ip += 5;
9903                                 ip += stloc_len;
9904                                 if (ins_flag & MONO_INST_VOLATILE) {
9905                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9906                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9907                                 }
9908                                 ins_flag = 0;
9909                                 break;
9910                         }
9911
9912                         /* Optimize the ldobj+stobj combination */
9913                         /* The reference case ends up being a load+store anyway */
9914                         /* Skip this if the operation is volatile. */
9915                         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)) {
9916                                 CHECK_STACK (1);
9917
9918                                 sp --;
9919
9920                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9921
9922                                 ip += 5 + 5;
9923                                 ins_flag = 0;
9924                                 break;
9925                         }
9926
9927                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9928                         ins->flags |= ins_flag;
9929                         *sp++ = ins;
9930
9931                         if (ins_flag & MONO_INST_VOLATILE) {
9932                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
9933                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
9934                         }
9935
9936                         ip += 5;
9937                         ins_flag = 0;
9938                         inline_costs += 1;
9939                         break;
9940                 }
9941                 case CEE_LDSTR:
9942                         CHECK_STACK_OVF (1);
9943                         CHECK_OPSIZE (5);
9944                         n = read32 (ip + 1);
9945
9946                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9947                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9948                                 ins->type = STACK_OBJ;
9949                                 *sp = ins;
9950                         }
9951                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9952                                 MonoInst *iargs [1];
9953                                 char *str = mono_method_get_wrapper_data (method, n);
9954
9955                                 if (cfg->compile_aot)
9956                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
9957                                 else
9958                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
9959                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9960                         } else {
9961                                 if (cfg->opt & MONO_OPT_SHARED) {
9962                                         MonoInst *iargs [3];
9963
9964                                         if (cfg->compile_aot) {
9965                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9966                                         }
9967                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9968                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9969                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9970                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9971                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9972                                 } else {
9973                                         if (bblock->out_of_line) {
9974                                                 MonoInst *iargs [2];
9975
9976                                                 if (image == mono_defaults.corlib) {
9977                                                         /* 
9978                                                          * Avoid relocations in AOT and save some space by using a 
9979                                                          * version of helper_ldstr specialized to mscorlib.
9980                                                          */
9981                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9982                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9983                                                 } else {
9984                                                         /* Avoid creating the string object */
9985                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9986                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9987                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9988                                                 }
9989                                         } 
9990                                         else
9991                                         if (cfg->compile_aot) {
9992                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9993                                                 *sp = ins;
9994                                                 MONO_ADD_INS (bblock, ins);
9995                                         } 
9996                                         else {
9997                                                 NEW_PCONST (cfg, ins, NULL);
9998                                                 ins->type = STACK_OBJ;
9999                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10000                                                 if (!ins->inst_p0)
10001                                                         OUT_OF_MEMORY_FAILURE;
10002
10003                                                 *sp = ins;
10004                                                 MONO_ADD_INS (bblock, ins);
10005                                         }
10006                                 }
10007                         }
10008
10009                         sp++;
10010                         ip += 5;
10011                         break;
10012                 case CEE_NEWOBJ: {
10013                         MonoInst *iargs [2];
10014                         MonoMethodSignature *fsig;
10015                         MonoInst this_ins;
10016                         MonoInst *alloc;
10017                         MonoInst *vtable_arg = NULL;
10018
10019                         CHECK_OPSIZE (5);
10020                         token = read32 (ip + 1);
10021                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10022                         if (!cmethod || mono_loader_get_last_error ())
10023                                 LOAD_ERROR;
10024                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10025                         CHECK_CFG_ERROR;
10026
10027                         mono_save_token_info (cfg, image, token, cmethod);
10028
10029                         if (!mono_class_init (cmethod->klass))
10030                                 TYPE_LOAD_ERROR (cmethod->klass);
10031
10032                         context_used = mini_method_check_context_used (cfg, cmethod);
10033
10034                         if (mono_security_cas_enabled ()) {
10035                                 if (check_linkdemand (cfg, method, cmethod))
10036                                         INLINE_FAILURE ("linkdemand");
10037                                 CHECK_CFG_EXCEPTION;
10038                         } else if (mono_security_core_clr_enabled ()) {
10039                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
10040                         }
10041
10042                         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)) {
10043                                 emit_generic_class_init (cfg, cmethod->klass);
10044                                 CHECK_TYPELOAD (cmethod->klass);
10045                         }
10046
10047                         /*
10048                         if (cfg->gsharedvt) {
10049                                 if (mini_is_gsharedvt_variable_signature (sig))
10050                                         GSHAREDVT_FAILURE (*ip);
10051                         }
10052                         */
10053
10054                         n = fsig->param_count;
10055                         CHECK_STACK (n);
10056
10057                         /* 
10058                          * Generate smaller code for the common newobj <exception> instruction in
10059                          * argument checking code.
10060                          */
10061                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10062                                 is_exception_class (cmethod->klass) && n <= 2 &&
10063                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10064                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10065                                 MonoInst *iargs [3];
10066
10067                                 sp -= n;
10068
10069                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10070                                 switch (n) {
10071                                 case 0:
10072                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10073                                         break;
10074                                 case 1:
10075                                         iargs [1] = sp [0];
10076                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10077                                         break;
10078                                 case 2:
10079                                         iargs [1] = sp [0];
10080                                         iargs [2] = sp [1];
10081                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10082                                         break;
10083                                 default:
10084                                         g_assert_not_reached ();
10085                                 }
10086
10087                                 ip += 5;
10088                                 inline_costs += 5;
10089                                 break;
10090                         }
10091
10092                         /* move the args to allow room for 'this' in the first position */
10093                         while (n--) {
10094                                 --sp;
10095                                 sp [1] = sp [0];
10096                         }
10097
10098                         /* check_call_signature () requires sp[0] to be set */
10099                         this_ins.type = STACK_OBJ;
10100                         sp [0] = &this_ins;
10101                         if (check_call_signature (cfg, fsig, sp))
10102                                 UNVERIFIED;
10103
10104                         iargs [0] = NULL;
10105
10106                         if (mini_class_is_system_array (cmethod->klass)) {
10107                                 *sp = emit_get_rgctx_method (cfg, context_used,
10108                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10109
10110                                 /* Avoid varargs in the common case */
10111                                 if (fsig->param_count == 1)
10112                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10113                                 else if (fsig->param_count == 2)
10114                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10115                                 else if (fsig->param_count == 3)
10116                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10117                                 else if (fsig->param_count == 4)
10118                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10119                                 else
10120                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10121                         } else if (cmethod->string_ctor) {
10122                                 g_assert (!context_used);
10123                                 g_assert (!vtable_arg);
10124                                 /* we simply pass a null pointer */
10125                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10126                                 /* now call the string ctor */
10127                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10128                         } else {
10129                                 if (cmethod->klass->valuetype) {
10130                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10131                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10132                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10133
10134                                         alloc = NULL;
10135
10136                                         /* 
10137                                          * The code generated by mini_emit_virtual_call () expects
10138                                          * iargs [0] to be a boxed instance, but luckily the vcall
10139                                          * will be transformed into a normal call there.
10140                                          */
10141                                 } else if (context_used) {
10142                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10143                                         *sp = alloc;
10144                                 } else {
10145                                         MonoVTable *vtable = NULL;
10146
10147                                         if (!cfg->compile_aot)
10148                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10149                                         CHECK_TYPELOAD (cmethod->klass);
10150
10151                                         /*
10152                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10153                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10154                                          * As a workaround, we call class cctors before allocating objects.
10155                                          */
10156                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10157                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
10158                                                 if (cfg->verbose_level > 2)
10159                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10160                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10161                                         }
10162
10163                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10164                                         *sp = alloc;
10165                                 }
10166                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10167
10168                                 if (alloc)
10169                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10170
10171                                 /* Now call the actual ctor */
10172                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &bblock, &inline_costs);
10173                                 CHECK_CFG_EXCEPTION;
10174                         }
10175
10176                         if (alloc == NULL) {
10177                                 /* Valuetype */
10178                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10179                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10180                                 *sp++= ins;
10181                         } else {
10182                                 *sp++ = alloc;
10183                         }
10184                         
10185                         ip += 5;
10186                         inline_costs += 5;
10187                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10188                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10189                         break;
10190                 }
10191                 case CEE_CASTCLASS:
10192                         CHECK_STACK (1);
10193                         --sp;
10194                         CHECK_OPSIZE (5);
10195                         token = read32 (ip + 1);
10196                         klass = mini_get_class (method, token, generic_context);
10197                         CHECK_TYPELOAD (klass);
10198                         if (sp [0]->type != STACK_OBJ)
10199                                 UNVERIFIED;
10200
10201                         ins = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10202                         CHECK_CFG_EXCEPTION;
10203
10204                         *sp ++ = ins;
10205                         ip += 5;
10206                         break;
10207                 case CEE_ISINST: {
10208                         CHECK_STACK (1);
10209                         --sp;
10210                         CHECK_OPSIZE (5);
10211                         token = read32 (ip + 1);
10212                         klass = mini_get_class (method, token, generic_context);
10213                         CHECK_TYPELOAD (klass);
10214                         if (sp [0]->type != STACK_OBJ)
10215                                 UNVERIFIED;
10216  
10217                         context_used = mini_class_check_context_used (cfg, klass);
10218
10219                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10220                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10221                                 MonoInst *args [3];
10222
10223                                 /* obj */
10224                                 args [0] = *sp;
10225
10226                                 /* klass */
10227                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10228
10229                                 /* inline cache*/
10230                                 if (cfg->compile_aot)
10231                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
10232                                 else
10233                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
10234
10235                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10236                                 ip += 5;
10237                                 inline_costs += 2;
10238                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10239                                 MonoMethod *mono_isinst;
10240                                 MonoInst *iargs [1];
10241                                 int costs;
10242
10243                                 mono_isinst = mono_marshal_get_isinst (klass); 
10244                                 iargs [0] = sp [0];
10245
10246                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10247                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10248                                 CHECK_CFG_EXCEPTION;
10249                                 g_assert (costs > 0);
10250                                 
10251                                 ip += 5;
10252                                 cfg->real_offset += 5;
10253
10254                                 *sp++= iargs [0];
10255
10256                                 inline_costs += costs;
10257                         }
10258                         else {
10259                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10260                                 CHECK_CFG_EXCEPTION;
10261                                 bblock = cfg->cbb;
10262                                 *sp ++ = ins;
10263                                 ip += 5;
10264                         }
10265                         break;
10266                 }
10267                 case CEE_UNBOX_ANY: {
10268                         MonoInst *res, *addr;
10269
10270                         CHECK_STACK (1);
10271                         --sp;
10272                         CHECK_OPSIZE (5);
10273                         token = read32 (ip + 1);
10274                         klass = mini_get_class (method, token, generic_context);
10275                         CHECK_TYPELOAD (klass);
10276  
10277                         mono_save_token_info (cfg, image, token, klass);
10278
10279                         context_used = mini_class_check_context_used (cfg, klass);
10280
10281                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10282                                 res = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
10283                                 inline_costs += 2;
10284                         } else if (generic_class_is_reference_type (cfg, klass)) {
10285                                 res = handle_castclass (cfg, klass, *sp, ip, &bblock, &inline_costs);
10286                                 CHECK_CFG_EXCEPTION;
10287                         } else if (mono_class_is_nullable (klass)) {
10288                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10289                         } else {
10290                                 addr = handle_unbox (cfg, klass, sp, context_used);
10291                                 /* LDOBJ */
10292                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10293                                 res = ins;
10294                                 inline_costs += 2;
10295                         }
10296
10297                         *sp ++ = res;
10298                         ip += 5;
10299                         break;
10300                 }
10301                 case CEE_BOX: {
10302                         MonoInst *val;
10303                         MonoClass *enum_class;
10304                         MonoMethod *has_flag;
10305
10306                         CHECK_STACK (1);
10307                         --sp;
10308                         val = *sp;
10309                         CHECK_OPSIZE (5);
10310                         token = read32 (ip + 1);
10311                         klass = mini_get_class (method, token, generic_context);
10312                         CHECK_TYPELOAD (klass);
10313
10314                         mono_save_token_info (cfg, image, token, klass);
10315
10316                         context_used = mini_class_check_context_used (cfg, klass);
10317
10318                         if (generic_class_is_reference_type (cfg, klass)) {
10319                                 *sp++ = val;
10320                                 ip += 5;
10321                                 break;
10322                         }
10323
10324                         if (klass == mono_defaults.void_class)
10325                                 UNVERIFIED;
10326                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10327                                 UNVERIFIED;
10328                         /* frequent check in generic code: box (struct), brtrue */
10329
10330                         /*
10331                          * Look for:
10332                          *
10333                          *   <push int/long ptr>
10334                          *   <push int/long>
10335                          *   box MyFlags
10336                          *   constrained. MyFlags
10337                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10338                          *
10339                          * If we find this sequence and the operand types on box and constrained
10340                          * are equal, we can emit a specialized instruction sequence instead of
10341                          * the very slow HasFlag () call.
10342                          */
10343                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10344                             /* Cheap checks first. */
10345                             ip + 5 + 6 + 5 < end &&
10346                             ip [5] == CEE_PREFIX1 &&
10347                             ip [6] == CEE_CONSTRAINED_ &&
10348                             ip [11] == CEE_CALLVIRT &&
10349                             ip_in_bb (cfg, bblock, ip + 5 + 6 + 5) &&
10350                             mono_class_is_enum (klass) &&
10351                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10352                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10353                             has_flag->klass == mono_defaults.enum_class &&
10354                             !strcmp (has_flag->name, "HasFlag") &&
10355                             has_flag->signature->hasthis &&
10356                             has_flag->signature->param_count == 1) {
10357                                 CHECK_TYPELOAD (enum_class);
10358
10359                                 if (enum_class == klass) {
10360                                         MonoInst *enum_this, *enum_flag;
10361
10362                                         ip += 5 + 6 + 5;
10363                                         --sp;
10364
10365                                         enum_this = sp [0];
10366                                         enum_flag = sp [1];
10367
10368                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10369                                         break;
10370                                 }
10371                         }
10372
10373                         // FIXME: LLVM can't handle the inconsistent bb linking
10374                         if (!mono_class_is_nullable (klass) &&
10375                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
10376                                 (ip [5] == CEE_BRTRUE || 
10377                                  ip [5] == CEE_BRTRUE_S ||
10378                                  ip [5] == CEE_BRFALSE ||
10379                                  ip [5] == CEE_BRFALSE_S)) {
10380                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10381                                 int dreg;
10382                                 MonoBasicBlock *true_bb, *false_bb;
10383
10384                                 ip += 5;
10385
10386                                 if (cfg->verbose_level > 3) {
10387                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10388                                         printf ("<box+brtrue opt>\n");
10389                                 }
10390
10391                                 switch (*ip) {
10392                                 case CEE_BRTRUE_S:
10393                                 case CEE_BRFALSE_S:
10394                                         CHECK_OPSIZE (2);
10395                                         ip++;
10396                                         target = ip + 1 + (signed char)(*ip);
10397                                         ip++;
10398                                         break;
10399                                 case CEE_BRTRUE:
10400                                 case CEE_BRFALSE:
10401                                         CHECK_OPSIZE (5);
10402                                         ip++;
10403                                         target = ip + 4 + (gint)(read32 (ip));
10404                                         ip += 4;
10405                                         break;
10406                                 default:
10407                                         g_assert_not_reached ();
10408                                 }
10409
10410                                 /* 
10411                                  * We need to link both bblocks, since it is needed for handling stack
10412                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10413                                  * Branching to only one of them would lead to inconsistencies, so
10414                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10415                                  */
10416                                 GET_BBLOCK (cfg, true_bb, target);
10417                                 GET_BBLOCK (cfg, false_bb, ip);
10418
10419                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10420                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10421
10422                                 if (sp != stack_start) {
10423                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10424                                         sp = stack_start;
10425                                         CHECK_UNVERIFIABLE (cfg);
10426                                 }
10427
10428                                 if (COMPILE_LLVM (cfg)) {
10429                                         dreg = alloc_ireg (cfg);
10430                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10431                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10432
10433                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10434                                 } else {
10435                                         /* The JIT can't eliminate the iconst+compare */
10436                                         MONO_INST_NEW (cfg, ins, OP_BR);
10437                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10438                                         MONO_ADD_INS (cfg->cbb, ins);
10439                                 }
10440
10441                                 start_new_bblock = 1;
10442                                 break;
10443                         }
10444
10445                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
10446
10447                         CHECK_CFG_EXCEPTION;
10448                         ip += 5;
10449                         inline_costs += 1;
10450                         break;
10451                 }
10452                 case CEE_UNBOX: {
10453                         CHECK_STACK (1);
10454                         --sp;
10455                         CHECK_OPSIZE (5);
10456                         token = read32 (ip + 1);
10457                         klass = mini_get_class (method, token, generic_context);
10458                         CHECK_TYPELOAD (klass);
10459
10460                         mono_save_token_info (cfg, image, token, klass);
10461
10462                         context_used = mini_class_check_context_used (cfg, klass);
10463
10464                         if (mono_class_is_nullable (klass)) {
10465                                 MonoInst *val;
10466
10467                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10468                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10469
10470                                 *sp++= ins;
10471                         } else {
10472                                 ins = handle_unbox (cfg, klass, sp, context_used);
10473                                 *sp++ = ins;
10474                         }
10475                         ip += 5;
10476                         inline_costs += 2;
10477                         break;
10478                 }
10479                 case CEE_LDFLD:
10480                 case CEE_LDFLDA:
10481                 case CEE_STFLD:
10482                 case CEE_LDSFLD:
10483                 case CEE_LDSFLDA:
10484                 case CEE_STSFLD: {
10485                         MonoClassField *field;
10486 #ifndef DISABLE_REMOTING
10487                         int costs;
10488 #endif
10489                         guint foffset;
10490                         gboolean is_instance;
10491                         int op;
10492                         gpointer addr = NULL;
10493                         gboolean is_special_static;
10494                         MonoType *ftype;
10495                         MonoInst *store_val = NULL;
10496                         MonoInst *thread_ins;
10497
10498                         op = *ip;
10499                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10500                         if (is_instance) {
10501                                 if (op == CEE_STFLD) {
10502                                         CHECK_STACK (2);
10503                                         sp -= 2;
10504                                         store_val = sp [1];
10505                                 } else {
10506                                         CHECK_STACK (1);
10507                                         --sp;
10508                                 }
10509                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10510                                         UNVERIFIED;
10511                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10512                                         UNVERIFIED;
10513                         } else {
10514                                 if (op == CEE_STSFLD) {
10515                                         CHECK_STACK (1);
10516                                         sp--;
10517                                         store_val = sp [0];
10518                                 }
10519                         }
10520
10521                         CHECK_OPSIZE (5);
10522                         token = read32 (ip + 1);
10523                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
10524                                 field = mono_method_get_wrapper_data (method, token);
10525                                 klass = field->parent;
10526                         }
10527                         else {
10528                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
10529                                 CHECK_CFG_ERROR;
10530                         }
10531                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
10532                                 FIELD_ACCESS_FAILURE (method, field);
10533                         mono_class_init (klass);
10534
10535                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
10536                                 UNVERIFIED;
10537
10538                         /* if the class is Critical then transparent code cannot access it's fields */
10539                         if (!is_instance && mono_security_core_clr_enabled ())
10540                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10541
10542                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
10543                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
10544                         if (mono_security_core_clr_enabled ())
10545                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
10546                         */
10547
10548                         /*
10549                          * LDFLD etc. is usable on static fields as well, so convert those cases to
10550                          * the static case.
10551                          */
10552                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
10553                                 switch (op) {
10554                                 case CEE_LDFLD:
10555                                         op = CEE_LDSFLD;
10556                                         break;
10557                                 case CEE_STFLD:
10558                                         op = CEE_STSFLD;
10559                                         break;
10560                                 case CEE_LDFLDA:
10561                                         op = CEE_LDSFLDA;
10562                                         break;
10563                                 default:
10564                                         g_assert_not_reached ();
10565                                 }
10566                                 is_instance = FALSE;
10567                         }
10568
10569                         context_used = mini_class_check_context_used (cfg, klass);
10570
10571                         /* INSTANCE CASE */
10572
10573                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
10574                         if (op == CEE_STFLD) {
10575                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
10576                                         UNVERIFIED;
10577 #ifndef DISABLE_REMOTING
10578                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
10579                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
10580                                         MonoInst *iargs [5];
10581
10582                                         GSHAREDVT_FAILURE (op);
10583
10584                                         iargs [0] = sp [0];
10585                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10586                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10587                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
10588                                                     field->offset);
10589                                         iargs [4] = sp [1];
10590
10591                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10592                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
10593                                                                                            iargs, ip, cfg->real_offset, TRUE, &bblock);
10594                                                 CHECK_CFG_EXCEPTION;
10595                                                 g_assert (costs > 0);
10596                                                       
10597                                                 cfg->real_offset += 5;
10598
10599                                                 inline_costs += costs;
10600                                         } else {
10601                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
10602                                         }
10603                                 } else
10604 #endif
10605                                 {
10606                                         MonoInst *store;
10607
10608                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10609
10610                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10611                                                 MonoInst *offset_ins;
10612
10613                                                 context_used = mini_class_check_context_used (cfg, klass);
10614
10615                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10616                                                 dreg = alloc_ireg_mp (cfg);
10617                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10618                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
10619                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
10620                                         } else {
10621                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
10622                                         }
10623                                         if (sp [0]->opcode != OP_LDADDR)
10624                                                 store->flags |= MONO_INST_FAULT;
10625
10626                                 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)) {
10627                                         /* insert call to write barrier */
10628                                         MonoInst *ptr;
10629                                         int dreg;
10630
10631                                         dreg = alloc_ireg_mp (cfg);
10632                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10633                                         emit_write_barrier (cfg, ptr, sp [1]);
10634                                 }
10635
10636                                         store->flags |= ins_flag;
10637                                 }
10638                                 ins_flag = 0;
10639                                 ip += 5;
10640                                 break;
10641                         }
10642
10643 #ifndef DISABLE_REMOTING
10644                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
10645                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
10646                                 MonoInst *iargs [4];
10647
10648                                 GSHAREDVT_FAILURE (op);
10649
10650                                 iargs [0] = sp [0];
10651                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10652                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
10653                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
10654                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
10655                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
10656                                                                                    iargs, ip, cfg->real_offset, TRUE, &bblock);
10657                                         CHECK_CFG_EXCEPTION;
10658                                         g_assert (costs > 0);
10659                                                       
10660                                         cfg->real_offset += 5;
10661
10662                                         *sp++ = iargs [0];
10663
10664                                         inline_costs += costs;
10665                                 } else {
10666                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
10667                                         *sp++ = ins;
10668                                 }
10669                         } else 
10670 #endif
10671                         if (is_instance) {
10672                                 if (sp [0]->type == STACK_VTYPE) {
10673                                         MonoInst *var;
10674
10675                                         /* Have to compute the address of the variable */
10676
10677                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
10678                                         if (!var)
10679                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
10680                                         else
10681                                                 g_assert (var->klass == klass);
10682                                         
10683                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
10684                                         sp [0] = ins;
10685                                 }
10686
10687                                 if (op == CEE_LDFLDA) {
10688                                         if (is_magic_tls_access (field)) {
10689                                                 GSHAREDVT_FAILURE (*ip);
10690                                                 ins = sp [0];
10691                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
10692                                         } else {
10693                                                 if (sp [0]->type == STACK_OBJ) {
10694                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
10695                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
10696                                                 }
10697
10698                                                 dreg = alloc_ireg_mp (cfg);
10699
10700                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10701                                                         MonoInst *offset_ins;
10702
10703                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10704                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10705                                                 } else {
10706                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
10707                                                 }
10708                                                 ins->klass = mono_class_from_mono_type (field->type);
10709                                                 ins->type = STACK_MP;
10710                                                 *sp++ = ins;
10711                                         }
10712                                 } else {
10713                                         MonoInst *load;
10714
10715                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
10716
10717                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10718                                                 MonoInst *offset_ins;
10719
10720                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10721                                                 dreg = alloc_ireg_mp (cfg);
10722                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
10723                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
10724                                         } else {
10725                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
10726                                         }
10727                                         load->flags |= ins_flag;
10728                                         if (sp [0]->opcode != OP_LDADDR)
10729                                                 load->flags |= MONO_INST_FAULT;
10730                                         *sp++ = load;
10731                                 }
10732                         }
10733
10734                         if (is_instance) {
10735                                 ins_flag = 0;
10736                                 ip += 5;
10737                                 break;
10738                         }
10739
10740                         /* STATIC CASE */
10741
10742                         /*
10743                          * We can only support shared generic static
10744                          * field access on architectures where the
10745                          * trampoline code has been extended to handle
10746                          * the generic class init.
10747                          */
10748 #ifndef MONO_ARCH_VTABLE_REG
10749                         GENERIC_SHARING_FAILURE (op);
10750 #endif
10751
10752                         context_used = mini_class_check_context_used (cfg, klass);
10753
10754                         ftype = mono_field_get_type (field);
10755
10756                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
10757                                 UNVERIFIED;
10758
10759                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
10760                          * to be called here.
10761                          */
10762                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
10763                                 mono_class_vtable (cfg->domain, klass);
10764                                 CHECK_TYPELOAD (klass);
10765                         }
10766                         mono_domain_lock (cfg->domain);
10767                         if (cfg->domain->special_static_fields)
10768                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
10769                         mono_domain_unlock (cfg->domain);
10770
10771                         is_special_static = mono_class_field_is_special_static (field);
10772
10773                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
10774                                 thread_ins = mono_get_thread_intrinsic (cfg);
10775                         else
10776                                 thread_ins = NULL;
10777
10778                         /* Generate IR to compute the field address */
10779                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
10780                                 /*
10781                                  * Fast access to TLS data
10782                                  * Inline version of get_thread_static_data () in
10783                                  * threads.c.
10784                                  */
10785                                 guint32 offset;
10786                                 int idx, static_data_reg, array_reg, dreg;
10787
10788                                 GSHAREDVT_FAILURE (op);
10789
10790                                 // offset &= 0x7fffffff;
10791                                 // idx = (offset >> 24) - 1;
10792                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10793                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10794                                 static_data_reg = alloc_ireg (cfg);
10795                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
10796
10797                                 if (cfg->compile_aot) {
10798                                         int offset_reg, offset2_reg, idx_reg;
10799
10800                                         /* For TLS variables, this will return the TLS offset */
10801                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10802                                         offset_reg = ins->dreg;
10803                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10804                                         idx_reg = alloc_ireg (cfg);
10805                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10806                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10807                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10808                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10809                                         array_reg = alloc_ireg (cfg);
10810                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10811                                         offset2_reg = alloc_ireg (cfg);
10812                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10813                                         dreg = alloc_ireg (cfg);
10814                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10815                                 } else {
10816                                         offset = (gsize)addr & 0x7fffffff;
10817                                         idx = (offset >> 24) - 1;
10818
10819                                         array_reg = alloc_ireg (cfg);
10820                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10821                                         dreg = alloc_ireg (cfg);
10822                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10823                                 }
10824                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10825                                         (cfg->compile_aot && is_special_static) ||
10826                                         (context_used && is_special_static)) {
10827                                 MonoInst *iargs [2];
10828
10829                                 g_assert (field->parent);
10830                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10831                                 if (context_used) {
10832                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10833                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10834                                 } else {
10835                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10836                                 }
10837                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10838                         } else if (context_used) {
10839                                 MonoInst *static_data;
10840
10841                                 /*
10842                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10843                                         method->klass->name_space, method->klass->name, method->name,
10844                                         depth, field->offset);
10845                                 */
10846
10847                                 if (mono_class_needs_cctor_run (klass, method))
10848                                         emit_generic_class_init (cfg, klass);
10849
10850                                 /*
10851                                  * The pointer we're computing here is
10852                                  *
10853                                  *   super_info.static_data + field->offset
10854                                  */
10855                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10856                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10857
10858                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10859                                         MonoInst *offset_ins;
10860
10861                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10862                                         dreg = alloc_ireg_mp (cfg);
10863                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10864                                 } else if (field->offset == 0) {
10865                                         ins = static_data;
10866                                 } else {
10867                                         int addr_reg = mono_alloc_preg (cfg);
10868                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10869                                 }
10870                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10871                                 MonoInst *iargs [2];
10872
10873                                 g_assert (field->parent);
10874                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10875                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10876                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10877                         } else {
10878                                 MonoVTable *vtable = NULL;
10879
10880                                 if (!cfg->compile_aot)
10881                                         vtable = mono_class_vtable (cfg->domain, klass);
10882                                 CHECK_TYPELOAD (klass);
10883
10884                                 if (!addr) {
10885                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10886                                                 if (!(g_slist_find (class_inits, klass))) {
10887                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10888                                                         if (cfg->verbose_level > 2)
10889                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10890                                                         class_inits = g_slist_prepend (class_inits, klass);
10891                                                 }
10892                                         } else {
10893                                                 if (cfg->run_cctors) {
10894                                                         MonoException *ex;
10895                                                         /* This makes so that inline cannot trigger */
10896                                                         /* .cctors: too many apps depend on them */
10897                                                         /* running with a specific order... */
10898                                                         g_assert (vtable);
10899                                                         if (! vtable->initialized)
10900                                                                 INLINE_FAILURE ("class init");
10901                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10902                                                         if (ex) {
10903                                                                 set_exception_object (cfg, ex);
10904                                                                 goto exception_exit;
10905                                                         }
10906                                                 }
10907                                         }
10908                                         if (cfg->compile_aot)
10909                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10910                                         else {
10911                                                 g_assert (vtable);
10912                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10913                                                 g_assert (addr);
10914                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10915                                         }
10916                                 } else {
10917                                         MonoInst *iargs [1];
10918                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10919                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10920                                 }
10921                         }
10922
10923                         /* Generate IR to do the actual load/store operation */
10924
10925                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
10926                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10927                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10928                         }
10929
10930                         if (op == CEE_LDSFLDA) {
10931                                 ins->klass = mono_class_from_mono_type (ftype);
10932                                 ins->type = STACK_PTR;
10933                                 *sp++ = ins;
10934                         } else if (op == CEE_STSFLD) {
10935                                 MonoInst *store;
10936
10937                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10938                                 store->flags |= ins_flag;
10939                         } else {
10940                                 gboolean is_const = FALSE;
10941                                 MonoVTable *vtable = NULL;
10942                                 gpointer addr = NULL;
10943
10944                                 if (!context_used) {
10945                                         vtable = mono_class_vtable (cfg->domain, klass);
10946                                         CHECK_TYPELOAD (klass);
10947                                 }
10948                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10949                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10950                                         int ro_type = ftype->type;
10951                                         if (!addr)
10952                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10953                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10954                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10955                                         }
10956
10957                                         GSHAREDVT_FAILURE (op);
10958
10959                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10960                                         is_const = TRUE;
10961                                         switch (ro_type) {
10962                                         case MONO_TYPE_BOOLEAN:
10963                                         case MONO_TYPE_U1:
10964                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10965                                                 sp++;
10966                                                 break;
10967                                         case MONO_TYPE_I1:
10968                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10969                                                 sp++;
10970                                                 break;                                          
10971                                         case MONO_TYPE_CHAR:
10972                                         case MONO_TYPE_U2:
10973                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10974                                                 sp++;
10975                                                 break;
10976                                         case MONO_TYPE_I2:
10977                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10978                                                 sp++;
10979                                                 break;
10980                                                 break;
10981                                         case MONO_TYPE_I4:
10982                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10983                                                 sp++;
10984                                                 break;                                          
10985                                         case MONO_TYPE_U4:
10986                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10987                                                 sp++;
10988                                                 break;
10989                                         case MONO_TYPE_I:
10990                                         case MONO_TYPE_U:
10991                                         case MONO_TYPE_PTR:
10992                                         case MONO_TYPE_FNPTR:
10993                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10994                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10995                                                 sp++;
10996                                                 break;
10997                                         case MONO_TYPE_STRING:
10998                                         case MONO_TYPE_OBJECT:
10999                                         case MONO_TYPE_CLASS:
11000                                         case MONO_TYPE_SZARRAY:
11001                                         case MONO_TYPE_ARRAY:
11002                                                 if (!mono_gc_is_moving ()) {
11003                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11004                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11005                                                         sp++;
11006                                                 } else {
11007                                                         is_const = FALSE;
11008                                                 }
11009                                                 break;
11010                                         case MONO_TYPE_I8:
11011                                         case MONO_TYPE_U8:
11012                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11013                                                 sp++;
11014                                                 break;
11015                                         case MONO_TYPE_R4:
11016                                         case MONO_TYPE_R8:
11017                                         case MONO_TYPE_VALUETYPE:
11018                                         default:
11019                                                 is_const = FALSE;
11020                                                 break;
11021                                         }
11022                                 }
11023
11024                                 if (!is_const) {
11025                                         MonoInst *load;
11026
11027                                         CHECK_STACK_OVF (1);
11028
11029                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11030                                         load->flags |= ins_flag;
11031                                         ins_flag = 0;
11032                                         *sp++ = load;
11033                                 }
11034                         }
11035
11036                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11037                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11038                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11039                         }
11040
11041                         ins_flag = 0;
11042                         ip += 5;
11043                         break;
11044                 }
11045                 case CEE_STOBJ:
11046                         CHECK_STACK (2);
11047                         sp -= 2;
11048                         CHECK_OPSIZE (5);
11049                         token = read32 (ip + 1);
11050                         klass = mini_get_class (method, token, generic_context);
11051                         CHECK_TYPELOAD (klass);
11052                         if (ins_flag & MONO_INST_VOLATILE) {
11053                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11054                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11055                         }
11056                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11057                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11058                         ins->flags |= ins_flag;
11059                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11060                                         generic_class_is_reference_type (cfg, klass)) {
11061                                 /* insert call to write barrier */
11062                                 emit_write_barrier (cfg, sp [0], sp [1]);
11063                         }
11064                         ins_flag = 0;
11065                         ip += 5;
11066                         inline_costs += 1;
11067                         break;
11068
11069                         /*
11070                          * Array opcodes
11071                          */
11072                 case CEE_NEWARR: {
11073                         MonoInst *len_ins;
11074                         const char *data_ptr;
11075                         int data_size = 0;
11076                         guint32 field_token;
11077
11078                         CHECK_STACK (1);
11079                         --sp;
11080
11081                         CHECK_OPSIZE (5);
11082                         token = read32 (ip + 1);
11083
11084                         klass = mini_get_class (method, token, generic_context);
11085                         CHECK_TYPELOAD (klass);
11086
11087                         context_used = mini_class_check_context_used (cfg, klass);
11088
11089                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11090                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11091                                 ins->sreg1 = sp [0]->dreg;
11092                                 ins->type = STACK_I4;
11093                                 ins->dreg = alloc_ireg (cfg);
11094                                 MONO_ADD_INS (cfg->cbb, ins);
11095                                 *sp = mono_decompose_opcode (cfg, ins);
11096                         }
11097
11098                         if (context_used) {
11099                                 MonoInst *args [3];
11100                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11101                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11102
11103                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11104
11105                                 /* vtable */
11106                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11107                                         array_class, MONO_RGCTX_INFO_VTABLE);
11108                                 /* array len */
11109                                 args [1] = sp [0];
11110
11111                                 if (managed_alloc)
11112                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11113                                 else
11114                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11115                         } else {
11116                                 if (cfg->opt & MONO_OPT_SHARED) {
11117                                         /* Decompose now to avoid problems with references to the domainvar */
11118                                         MonoInst *iargs [3];
11119
11120                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11121                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11122                                         iargs [2] = sp [0];
11123
11124                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11125                                 } else {
11126                                         /* Decompose later since it is needed by abcrem */
11127                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11128                                         mono_class_vtable (cfg->domain, array_type);
11129                                         CHECK_TYPELOAD (array_type);
11130
11131                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11132                                         ins->dreg = alloc_ireg_ref (cfg);
11133                                         ins->sreg1 = sp [0]->dreg;
11134                                         ins->inst_newa_class = klass;
11135                                         ins->type = STACK_OBJ;
11136                                         ins->klass = array_type;
11137                                         MONO_ADD_INS (cfg->cbb, ins);
11138                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11139                                         cfg->cbb->has_array_access = TRUE;
11140
11141                                         /* Needed so mono_emit_load_get_addr () gets called */
11142                                         mono_get_got_var (cfg);
11143                                 }
11144                         }
11145
11146                         len_ins = sp [0];
11147                         ip += 5;
11148                         *sp++ = ins;
11149                         inline_costs += 1;
11150
11151                         /* 
11152                          * we inline/optimize the initialization sequence if possible.
11153                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11154                          * for small sizes open code the memcpy
11155                          * ensure the rva field is big enough
11156                          */
11157                         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))) {
11158                                 MonoMethod *memcpy_method = get_memcpy_method ();
11159                                 MonoInst *iargs [3];
11160                                 int add_reg = alloc_ireg_mp (cfg);
11161
11162                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11163                                 if (cfg->compile_aot) {
11164                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11165                                 } else {
11166                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11167                                 }
11168                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11169                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11170                                 ip += 11;
11171                         }
11172
11173                         break;
11174                 }
11175                 case CEE_LDLEN:
11176                         CHECK_STACK (1);
11177                         --sp;
11178                         if (sp [0]->type != STACK_OBJ)
11179                                 UNVERIFIED;
11180
11181                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11182                         ins->dreg = alloc_preg (cfg);
11183                         ins->sreg1 = sp [0]->dreg;
11184                         ins->type = STACK_I4;
11185                         /* This flag will be inherited by the decomposition */
11186                         ins->flags |= MONO_INST_FAULT;
11187                         MONO_ADD_INS (cfg->cbb, ins);
11188                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11189                         cfg->cbb->has_array_access = TRUE;
11190                         ip ++;
11191                         *sp++ = ins;
11192                         break;
11193                 case CEE_LDELEMA:
11194                         CHECK_STACK (2);
11195                         sp -= 2;
11196                         CHECK_OPSIZE (5);
11197                         if (sp [0]->type != STACK_OBJ)
11198                                 UNVERIFIED;
11199
11200                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11201
11202                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11203                         CHECK_TYPELOAD (klass);
11204                         /* we need to make sure that this array is exactly the type it needs
11205                          * to be for correctness. the wrappers are lax with their usage
11206                          * so we need to ignore them here
11207                          */
11208                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11209                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11210                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11211                                 CHECK_TYPELOAD (array_class);
11212                         }
11213
11214                         readonly = FALSE;
11215                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11216                         *sp++ = ins;
11217                         ip += 5;
11218                         break;
11219                 case CEE_LDELEM:
11220                 case CEE_LDELEM_I1:
11221                 case CEE_LDELEM_U1:
11222                 case CEE_LDELEM_I2:
11223                 case CEE_LDELEM_U2:
11224                 case CEE_LDELEM_I4:
11225                 case CEE_LDELEM_U4:
11226                 case CEE_LDELEM_I8:
11227                 case CEE_LDELEM_I:
11228                 case CEE_LDELEM_R4:
11229                 case CEE_LDELEM_R8:
11230                 case CEE_LDELEM_REF: {
11231                         MonoInst *addr;
11232
11233                         CHECK_STACK (2);
11234                         sp -= 2;
11235
11236                         if (*ip == CEE_LDELEM) {
11237                                 CHECK_OPSIZE (5);
11238                                 token = read32 (ip + 1);
11239                                 klass = mini_get_class (method, token, generic_context);
11240                                 CHECK_TYPELOAD (klass);
11241                                 mono_class_init (klass);
11242                         }
11243                         else
11244                                 klass = array_access_to_klass (*ip);
11245
11246                         if (sp [0]->type != STACK_OBJ)
11247                                 UNVERIFIED;
11248
11249                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11250
11251                         if (mini_is_gsharedvt_variable_klass (cfg, klass)) {
11252                                 // FIXME-VT: OP_ICONST optimization
11253                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11254                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11255                                 ins->opcode = OP_LOADV_MEMBASE;
11256                         } else if (sp [1]->opcode == OP_ICONST) {
11257                                 int array_reg = sp [0]->dreg;
11258                                 int index_reg = sp [1]->dreg;
11259                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11260
11261                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11262                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11263                         } else {
11264                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11265                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11266                         }
11267                         *sp++ = ins;
11268                         if (*ip == CEE_LDELEM)
11269                                 ip += 5;
11270                         else
11271                                 ++ip;
11272                         break;
11273                 }
11274                 case CEE_STELEM_I:
11275                 case CEE_STELEM_I1:
11276                 case CEE_STELEM_I2:
11277                 case CEE_STELEM_I4:
11278                 case CEE_STELEM_I8:
11279                 case CEE_STELEM_R4:
11280                 case CEE_STELEM_R8:
11281                 case CEE_STELEM_REF:
11282                 case CEE_STELEM: {
11283                         CHECK_STACK (3);
11284                         sp -= 3;
11285
11286                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11287
11288                         if (*ip == CEE_STELEM) {
11289                                 CHECK_OPSIZE (5);
11290                                 token = read32 (ip + 1);
11291                                 klass = mini_get_class (method, token, generic_context);
11292                                 CHECK_TYPELOAD (klass);
11293                                 mono_class_init (klass);
11294                         }
11295                         else
11296                                 klass = array_access_to_klass (*ip);
11297
11298                         if (sp [0]->type != STACK_OBJ)
11299                                 UNVERIFIED;
11300
11301                         emit_array_store (cfg, klass, sp, TRUE);
11302
11303                         if (*ip == CEE_STELEM)
11304                                 ip += 5;
11305                         else
11306                                 ++ip;
11307                         inline_costs += 1;
11308                         break;
11309                 }
11310                 case CEE_CKFINITE: {
11311                         CHECK_STACK (1);
11312                         --sp;
11313
11314                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11315                         ins->sreg1 = sp [0]->dreg;
11316                         ins->dreg = alloc_freg (cfg);
11317                         ins->type = STACK_R8;
11318                         MONO_ADD_INS (bblock, ins);
11319
11320                         *sp++ = mono_decompose_opcode (cfg, ins);
11321
11322                         ++ip;
11323                         break;
11324                 }
11325                 case CEE_REFANYVAL: {
11326                         MonoInst *src_var, *src;
11327
11328                         int klass_reg = alloc_preg (cfg);
11329                         int dreg = alloc_preg (cfg);
11330
11331                         GSHAREDVT_FAILURE (*ip);
11332
11333                         CHECK_STACK (1);
11334                         MONO_INST_NEW (cfg, ins, *ip);
11335                         --sp;
11336                         CHECK_OPSIZE (5);
11337                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11338                         CHECK_TYPELOAD (klass);
11339
11340                         context_used = mini_class_check_context_used (cfg, klass);
11341
11342                         // FIXME:
11343                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11344                         if (!src_var)
11345                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11346                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11347                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11348
11349                         if (context_used) {
11350                                 MonoInst *klass_ins;
11351
11352                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11353                                                 klass, MONO_RGCTX_INFO_KLASS);
11354
11355                                 // FIXME:
11356                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11357                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11358                         } else {
11359                                 mini_emit_class_check (cfg, klass_reg, klass);
11360                         }
11361                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11362                         ins->type = STACK_MP;
11363                         *sp++ = ins;
11364                         ip += 5;
11365                         break;
11366                 }
11367                 case CEE_MKREFANY: {
11368                         MonoInst *loc, *addr;
11369
11370                         GSHAREDVT_FAILURE (*ip);
11371
11372                         CHECK_STACK (1);
11373                         MONO_INST_NEW (cfg, ins, *ip);
11374                         --sp;
11375                         CHECK_OPSIZE (5);
11376                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11377                         CHECK_TYPELOAD (klass);
11378
11379                         context_used = mini_class_check_context_used (cfg, klass);
11380
11381                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11382                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11383
11384                         if (context_used) {
11385                                 MonoInst *const_ins;
11386                                 int type_reg = alloc_preg (cfg);
11387
11388                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11389                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11390                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11391                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11392                         } else if (cfg->compile_aot) {
11393                                 int const_reg = alloc_preg (cfg);
11394                                 int type_reg = alloc_preg (cfg);
11395
11396                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11397                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11398                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11399                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11400                         } else {
11401                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11402                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11403                         }
11404                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11405
11406                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11407                         ins->type = STACK_VTYPE;
11408                         ins->klass = mono_defaults.typed_reference_class;
11409                         *sp++ = ins;
11410                         ip += 5;
11411                         break;
11412                 }
11413                 case CEE_LDTOKEN: {
11414                         gpointer handle;
11415                         MonoClass *handle_class;
11416
11417                         CHECK_STACK_OVF (1);
11418
11419                         CHECK_OPSIZE (5);
11420                         n = read32 (ip + 1);
11421
11422                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11423                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11424                                 handle = mono_method_get_wrapper_data (method, n);
11425                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
11426                                 if (handle_class == mono_defaults.typehandle_class)
11427                                         handle = &((MonoClass*)handle)->byval_arg;
11428                         }
11429                         else {
11430                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11431                                 CHECK_CFG_ERROR;
11432                         }
11433                         if (!handle)
11434                                 LOAD_ERROR;
11435                         mono_class_init (handle_class);
11436                         if (cfg->generic_sharing_context) {
11437                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11438                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11439                                         /* This case handles ldtoken
11440                                            of an open type, like for
11441                                            typeof(Gen<>). */
11442                                         context_used = 0;
11443                                 } else if (handle_class == mono_defaults.typehandle_class) {
11444                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
11445                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11446                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11447                                 else if (handle_class == mono_defaults.methodhandle_class)
11448                                         context_used = mini_method_check_context_used (cfg, handle);
11449                                 else
11450                                         g_assert_not_reached ();
11451                         }
11452
11453                         if ((cfg->opt & MONO_OPT_SHARED) &&
11454                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11455                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11456                                 MonoInst *addr, *vtvar, *iargs [3];
11457                                 int method_context_used;
11458
11459                                 method_context_used = mini_method_check_context_used (cfg, method);
11460
11461                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11462
11463                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11464                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11465                                 if (method_context_used) {
11466                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11467                                                 method, MONO_RGCTX_INFO_METHOD);
11468                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11469                                 } else {
11470                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11471                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11472                                 }
11473                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11474
11475                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11476
11477                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11478                         } else {
11479                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
11480                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11481                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11482                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11483                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11484                                         MonoClass *tclass = mono_class_from_mono_type (handle);
11485
11486                                         mono_class_init (tclass);
11487                                         if (context_used) {
11488                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11489                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11490                                         } else if (cfg->compile_aot) {
11491                                                 if (method->wrapper_type) {
11492                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11493                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11494                                                                 /* Special case for static synchronized wrappers */
11495                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11496                                                         } else {
11497                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11498                                                                 /* FIXME: n is not a normal token */
11499                                                                 DISABLE_AOT (cfg);
11500                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11501                                                         }
11502                                                 } else {
11503                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11504                                                 }
11505                                         } else {
11506                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
11507                                         }
11508                                         ins->type = STACK_OBJ;
11509                                         ins->klass = cmethod->klass;
11510                                         ip += 5;
11511                                 } else {
11512                                         MonoInst *addr, *vtvar;
11513
11514                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11515
11516                                         if (context_used) {
11517                                                 if (handle_class == mono_defaults.typehandle_class) {
11518                                                         ins = emit_get_rgctx_klass (cfg, context_used,
11519                                                                         mono_class_from_mono_type (handle),
11520                                                                         MONO_RGCTX_INFO_TYPE);
11521                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
11522                                                         ins = emit_get_rgctx_method (cfg, context_used,
11523                                                                         handle, MONO_RGCTX_INFO_METHOD);
11524                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
11525                                                         ins = emit_get_rgctx_field (cfg, context_used,
11526                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
11527                                                 } else {
11528                                                         g_assert_not_reached ();
11529                                                 }
11530                                         } else if (cfg->compile_aot) {
11531                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
11532                                         } else {
11533                                                 EMIT_NEW_PCONST (cfg, ins, handle);
11534                                         }
11535                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11536                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11537                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11538                                 }
11539                         }
11540
11541                         *sp++ = ins;
11542                         ip += 5;
11543                         break;
11544                 }
11545                 case CEE_THROW:
11546                         CHECK_STACK (1);
11547                         MONO_INST_NEW (cfg, ins, OP_THROW);
11548                         --sp;
11549                         ins->sreg1 = sp [0]->dreg;
11550                         ip++;
11551                         bblock->out_of_line = TRUE;
11552                         MONO_ADD_INS (bblock, ins);
11553                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11554                         MONO_ADD_INS (bblock, ins);
11555                         sp = stack_start;
11556                         
11557                         link_bblock (cfg, bblock, end_bblock);
11558                         start_new_bblock = 1;
11559                         break;
11560                 case CEE_ENDFINALLY:
11561                         /* mono_save_seq_point_info () depends on this */
11562                         if (sp != stack_start)
11563                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
11564                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
11565                         MONO_ADD_INS (bblock, ins);
11566                         ip++;
11567                         start_new_bblock = 1;
11568
11569                         /*
11570                          * Control will leave the method so empty the stack, otherwise
11571                          * the next basic block will start with a nonempty stack.
11572                          */
11573                         while (sp != stack_start) {
11574                                 sp--;
11575                         }
11576                         break;
11577                 case CEE_LEAVE:
11578                 case CEE_LEAVE_S: {
11579                         GList *handlers;
11580
11581                         if (*ip == CEE_LEAVE) {
11582                                 CHECK_OPSIZE (5);
11583                                 target = ip + 5 + (gint32)read32(ip + 1);
11584                         } else {
11585                                 CHECK_OPSIZE (2);
11586                                 target = ip + 2 + (signed char)(ip [1]);
11587                         }
11588
11589                         /* empty the stack */
11590                         while (sp != stack_start) {
11591                                 sp--;
11592                         }
11593
11594                         /* 
11595                          * If this leave statement is in a catch block, check for a
11596                          * pending exception, and rethrow it if necessary.
11597                          * We avoid doing this in runtime invoke wrappers, since those are called
11598                          * by native code which excepts the wrapper to catch all exceptions.
11599                          */
11600                         for (i = 0; i < header->num_clauses; ++i) {
11601                                 MonoExceptionClause *clause = &header->clauses [i];
11602
11603                                 /* 
11604                                  * Use <= in the final comparison to handle clauses with multiple
11605                                  * leave statements, like in bug #78024.
11606                                  * The ordering of the exception clauses guarantees that we find the
11607                                  * innermost clause.
11608                                  */
11609                                 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) {
11610                                         MonoInst *exc_ins;
11611                                         MonoBasicBlock *dont_throw;
11612
11613                                         /*
11614                                           MonoInst *load;
11615
11616                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
11617                                         */
11618
11619                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
11620
11621                                         NEW_BBLOCK (cfg, dont_throw);
11622
11623                                         /*
11624                                          * Currently, we always rethrow the abort exception, despite the 
11625                                          * fact that this is not correct. See thread6.cs for an example. 
11626                                          * But propagating the abort exception is more important than 
11627                                          * getting the sematics right.
11628                                          */
11629                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
11630                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
11631                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
11632
11633                                         MONO_START_BB (cfg, dont_throw);
11634                                         bblock = cfg->cbb;
11635                                 }
11636                         }
11637
11638                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
11639                                 GList *tmp;
11640                                 MonoExceptionClause *clause;
11641
11642                                 for (tmp = handlers; tmp; tmp = tmp->next) {
11643                                         clause = tmp->data;
11644                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
11645                                         g_assert (tblock);
11646                                         link_bblock (cfg, bblock, tblock);
11647                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
11648                                         ins->inst_target_bb = tblock;
11649                                         ins->inst_eh_block = clause;
11650                                         MONO_ADD_INS (bblock, ins);
11651                                         bblock->has_call_handler = 1;
11652                                         if (COMPILE_LLVM (cfg)) {
11653                                                 MonoBasicBlock *target_bb;
11654
11655                                                 /* 
11656                                                  * Link the finally bblock with the target, since it will
11657                                                  * conceptually branch there.
11658                                                  * FIXME: Have to link the bblock containing the endfinally.
11659                                                  */
11660                                                 GET_BBLOCK (cfg, target_bb, target);
11661                                                 link_bblock (cfg, tblock, target_bb);
11662                                         }
11663                                 }
11664                                 g_list_free (handlers);
11665                         } 
11666
11667                         MONO_INST_NEW (cfg, ins, OP_BR);
11668                         MONO_ADD_INS (bblock, ins);
11669                         GET_BBLOCK (cfg, tblock, target);
11670                         link_bblock (cfg, bblock, tblock);
11671                         ins->inst_target_bb = tblock;
11672                         start_new_bblock = 1;
11673
11674                         if (*ip == CEE_LEAVE)
11675                                 ip += 5;
11676                         else
11677                                 ip += 2;
11678
11679                         break;
11680                 }
11681
11682                         /*
11683                          * Mono specific opcodes
11684                          */
11685                 case MONO_CUSTOM_PREFIX: {
11686
11687                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
11688
11689                         CHECK_OPSIZE (2);
11690                         switch (ip [1]) {
11691                         case CEE_MONO_ICALL: {
11692                                 gpointer func;
11693                                 MonoJitICallInfo *info;
11694
11695                                 token = read32 (ip + 2);
11696                                 func = mono_method_get_wrapper_data (method, token);
11697                                 info = mono_find_jit_icall_by_addr (func);
11698                                 if (!info)
11699                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
11700                                 g_assert (info);
11701
11702                                 CHECK_STACK (info->sig->param_count);
11703                                 sp -= info->sig->param_count;
11704
11705                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
11706                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
11707                                         *sp++ = ins;
11708
11709                                 ip += 6;
11710                                 inline_costs += 10 * num_calls++;
11711
11712                                 break;
11713                         }
11714                         case CEE_MONO_LDPTR: {
11715                                 gpointer ptr;
11716
11717                                 CHECK_STACK_OVF (1);
11718                                 CHECK_OPSIZE (6);
11719                                 token = read32 (ip + 2);
11720
11721                                 ptr = mono_method_get_wrapper_data (method, token);
11722                                 /* FIXME: Generalize this */
11723                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
11724                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
11725                                         *sp++ = ins;
11726                                         ip += 6;
11727                                         break;
11728                                 }
11729                                 EMIT_NEW_PCONST (cfg, ins, ptr);
11730                                 *sp++ = ins;
11731                                 ip += 6;
11732                                 inline_costs += 10 * num_calls++;
11733                                 /* Can't embed random pointers into AOT code */
11734                                 DISABLE_AOT (cfg);
11735                                 break;
11736                         }
11737                         case CEE_MONO_JIT_ICALL_ADDR: {
11738                                 MonoJitICallInfo *callinfo;
11739                                 gpointer ptr;
11740
11741                                 CHECK_STACK_OVF (1);
11742                                 CHECK_OPSIZE (6);
11743                                 token = read32 (ip + 2);
11744
11745                                 ptr = mono_method_get_wrapper_data (method, token);
11746                                 callinfo = mono_find_jit_icall_by_addr (ptr);
11747                                 g_assert (callinfo);
11748                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
11749                                 *sp++ = ins;
11750                                 ip += 6;
11751                                 inline_costs += 10 * num_calls++;
11752                                 break;
11753                         }
11754                         case CEE_MONO_ICALL_ADDR: {
11755                                 MonoMethod *cmethod;
11756                                 gpointer ptr;
11757
11758                                 CHECK_STACK_OVF (1);
11759                                 CHECK_OPSIZE (6);
11760                                 token = read32 (ip + 2);
11761
11762                                 cmethod = mono_method_get_wrapper_data (method, token);
11763
11764                                 if (cfg->compile_aot) {
11765                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
11766                                 } else {
11767                                         ptr = mono_lookup_internal_call (cmethod);
11768                                         g_assert (ptr);
11769                                         EMIT_NEW_PCONST (cfg, ins, ptr);
11770                                 }
11771                                 *sp++ = ins;
11772                                 ip += 6;
11773                                 break;
11774                         }
11775                         case CEE_MONO_VTADDR: {
11776                                 MonoInst *src_var, *src;
11777
11778                                 CHECK_STACK (1);
11779                                 --sp;
11780
11781                                 // FIXME:
11782                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11783                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
11784                                 *sp++ = src;
11785                                 ip += 2;
11786                                 break;
11787                         }
11788                         case CEE_MONO_NEWOBJ: {
11789                                 MonoInst *iargs [2];
11790
11791                                 CHECK_STACK_OVF (1);
11792                                 CHECK_OPSIZE (6);
11793                                 token = read32 (ip + 2);
11794                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11795                                 mono_class_init (klass);
11796                                 NEW_DOMAINCONST (cfg, iargs [0]);
11797                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11798                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11799                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11800                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11801                                 ip += 6;
11802                                 inline_costs += 10 * num_calls++;
11803                                 break;
11804                         }
11805                         case CEE_MONO_OBJADDR:
11806                                 CHECK_STACK (1);
11807                                 --sp;
11808                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11809                                 ins->dreg = alloc_ireg_mp (cfg);
11810                                 ins->sreg1 = sp [0]->dreg;
11811                                 ins->type = STACK_MP;
11812                                 MONO_ADD_INS (cfg->cbb, ins);
11813                                 *sp++ = ins;
11814                                 ip += 2;
11815                                 break;
11816                         case CEE_MONO_LDNATIVEOBJ:
11817                                 /*
11818                                  * Similar to LDOBJ, but instead load the unmanaged 
11819                                  * representation of the vtype to the stack.
11820                                  */
11821                                 CHECK_STACK (1);
11822                                 CHECK_OPSIZE (6);
11823                                 --sp;
11824                                 token = read32 (ip + 2);
11825                                 klass = mono_method_get_wrapper_data (method, token);
11826                                 g_assert (klass->valuetype);
11827                                 mono_class_init (klass);
11828
11829                                 {
11830                                         MonoInst *src, *dest, *temp;
11831
11832                                         src = sp [0];
11833                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11834                                         temp->backend.is_pinvoke = 1;
11835                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11836                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11837
11838                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11839                                         dest->type = STACK_VTYPE;
11840                                         dest->klass = klass;
11841
11842                                         *sp ++ = dest;
11843                                         ip += 6;
11844                                 }
11845                                 break;
11846                         case CEE_MONO_RETOBJ: {
11847                                 /*
11848                                  * Same as RET, but return the native representation of a vtype
11849                                  * to the caller.
11850                                  */
11851                                 g_assert (cfg->ret);
11852                                 g_assert (mono_method_signature (method)->pinvoke); 
11853                                 CHECK_STACK (1);
11854                                 --sp;
11855                                 
11856                                 CHECK_OPSIZE (6);
11857                                 token = read32 (ip + 2);    
11858                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11859
11860                                 if (!cfg->vret_addr) {
11861                                         g_assert (cfg->ret_var_is_local);
11862
11863                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11864                                 } else {
11865                                         EMIT_NEW_RETLOADA (cfg, ins);
11866                                 }
11867                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11868                                 
11869                                 if (sp != stack_start)
11870                                         UNVERIFIED;
11871                                 
11872                                 MONO_INST_NEW (cfg, ins, OP_BR);
11873                                 ins->inst_target_bb = end_bblock;
11874                                 MONO_ADD_INS (bblock, ins);
11875                                 link_bblock (cfg, bblock, end_bblock);
11876                                 start_new_bblock = 1;
11877                                 ip += 6;
11878                                 break;
11879                         }
11880                         case CEE_MONO_CISINST:
11881                         case CEE_MONO_CCASTCLASS: {
11882                                 int token;
11883                                 CHECK_STACK (1);
11884                                 --sp;
11885                                 CHECK_OPSIZE (6);
11886                                 token = read32 (ip + 2);
11887                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11888                                 if (ip [1] == CEE_MONO_CISINST)
11889                                         ins = handle_cisinst (cfg, klass, sp [0]);
11890                                 else
11891                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11892                                 bblock = cfg->cbb;
11893                                 *sp++ = ins;
11894                                 ip += 6;
11895                                 break;
11896                         }
11897                         case CEE_MONO_SAVE_LMF:
11898                         case CEE_MONO_RESTORE_LMF:
11899 #ifdef MONO_ARCH_HAVE_LMF_OPS
11900                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11901                                 MONO_ADD_INS (bblock, ins);
11902                                 cfg->need_lmf_area = TRUE;
11903 #endif
11904                                 ip += 2;
11905                                 break;
11906                         case CEE_MONO_CLASSCONST:
11907                                 CHECK_STACK_OVF (1);
11908                                 CHECK_OPSIZE (6);
11909                                 token = read32 (ip + 2);
11910                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11911                                 *sp++ = ins;
11912                                 ip += 6;
11913                                 inline_costs += 10 * num_calls++;
11914                                 break;
11915                         case CEE_MONO_NOT_TAKEN:
11916                                 bblock->out_of_line = TRUE;
11917                                 ip += 2;
11918                                 break;
11919                         case CEE_MONO_TLS: {
11920                                 int key;
11921
11922                                 CHECK_STACK_OVF (1);
11923                                 CHECK_OPSIZE (6);
11924                                 key = (gint32)read32 (ip + 2);
11925                                 g_assert (key < TLS_KEY_NUM);
11926
11927                                 ins = mono_create_tls_get (cfg, key);
11928                                 if (!ins) {
11929                                         if (cfg->compile_aot) {
11930                                                 DISABLE_AOT (cfg);
11931                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11932                                                 ins->dreg = alloc_preg (cfg);
11933                                                 ins->type = STACK_PTR;
11934                                         } else {
11935                                                 g_assert_not_reached ();
11936                                         }
11937                                 }
11938                                 ins->type = STACK_PTR;
11939                                 MONO_ADD_INS (bblock, ins);
11940                                 *sp++ = ins;
11941                                 ip += 6;
11942                                 break;
11943                         }
11944                         case CEE_MONO_DYN_CALL: {
11945                                 MonoCallInst *call;
11946
11947                                 /* It would be easier to call a trampoline, but that would put an
11948                                  * extra frame on the stack, confusing exception handling. So
11949                                  * implement it inline using an opcode for now.
11950                                  */
11951
11952                                 if (!cfg->dyn_call_var) {
11953                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11954                                         /* prevent it from being register allocated */
11955                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
11956                                 }
11957
11958                                 /* Has to use a call inst since it local regalloc expects it */
11959                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11960                                 ins = (MonoInst*)call;
11961                                 sp -= 2;
11962                                 ins->sreg1 = sp [0]->dreg;
11963                                 ins->sreg2 = sp [1]->dreg;
11964                                 MONO_ADD_INS (bblock, ins);
11965
11966                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11967
11968                                 ip += 2;
11969                                 inline_costs += 10 * num_calls++;
11970
11971                                 break;
11972                         }
11973                         case CEE_MONO_MEMORY_BARRIER: {
11974                                 CHECK_OPSIZE (6);
11975                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
11976                                 ip += 6;
11977                                 break;
11978                         }
11979                         case CEE_MONO_JIT_ATTACH: {
11980                                 MonoInst *args [16], *domain_ins;
11981                                 MonoInst *ad_ins, *jit_tls_ins;
11982                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
11983
11984                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11985
11986                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11987                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11988
11989                                 ad_ins = mono_get_domain_intrinsic (cfg);
11990                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
11991
11992                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && jit_tls_ins) {
11993                                         NEW_BBLOCK (cfg, next_bb);
11994                                         NEW_BBLOCK (cfg, call_bb);
11995
11996                                         if (cfg->compile_aot) {
11997                                                 /* AOT code is only used in the root domain */
11998                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
11999                                         } else {
12000                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12001                                         }
12002                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12003                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12004                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12005
12006                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12007                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12008                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12009
12010                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12011                                         MONO_START_BB (cfg, call_bb);
12012                                 }
12013
12014                                 if (cfg->compile_aot) {
12015                                         /* AOT code is only used in the root domain */
12016                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12017                                 } else {
12018                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12019                                 }
12020                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12021                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12022
12023                                 if (next_bb) {
12024                                         MONO_START_BB (cfg, next_bb);
12025                                         bblock = cfg->cbb;
12026                                 }
12027                                 ip += 2;
12028                                 break;
12029                         }
12030                         case CEE_MONO_JIT_DETACH: {
12031                                 MonoInst *args [16];
12032
12033                                 /* Restore the original domain */
12034                                 dreg = alloc_ireg (cfg);
12035                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12036                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12037                                 ip += 2;
12038                                 break;
12039                         }
12040                         default:
12041                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12042                                 break;
12043                         }
12044                         break;
12045                 }
12046
12047                 case CEE_PREFIX1: {
12048                         CHECK_OPSIZE (2);
12049                         switch (ip [1]) {
12050                         case CEE_ARGLIST: {
12051                                 /* somewhat similar to LDTOKEN */
12052                                 MonoInst *addr, *vtvar;
12053                                 CHECK_STACK_OVF (1);
12054                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12055
12056                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12057                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12058
12059                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12060                                 ins->type = STACK_VTYPE;
12061                                 ins->klass = mono_defaults.argumenthandle_class;
12062                                 *sp++ = ins;
12063                                 ip += 2;
12064                                 break;
12065                         }
12066                         case CEE_CEQ:
12067                         case CEE_CGT:
12068                         case CEE_CGT_UN:
12069                         case CEE_CLT:
12070                         case CEE_CLT_UN: {
12071                                 MonoInst *cmp;
12072                                 CHECK_STACK (2);
12073                                 /*
12074                                  * The following transforms:
12075                                  *    CEE_CEQ    into OP_CEQ
12076                                  *    CEE_CGT    into OP_CGT
12077                                  *    CEE_CGT_UN into OP_CGT_UN
12078                                  *    CEE_CLT    into OP_CLT
12079                                  *    CEE_CLT_UN into OP_CLT_UN
12080                                  */
12081                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12082                                 
12083                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12084                                 sp -= 2;
12085                                 cmp->sreg1 = sp [0]->dreg;
12086                                 cmp->sreg2 = sp [1]->dreg;
12087                                 type_from_op (cmp, sp [0], sp [1]);
12088                                 CHECK_TYPE (cmp);
12089                                 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))))
12090                                         cmp->opcode = OP_LCOMPARE;
12091                                 else if (sp [0]->type == STACK_R8)
12092                                         cmp->opcode = OP_FCOMPARE;
12093                                 else
12094                                         cmp->opcode = OP_ICOMPARE;
12095                                 MONO_ADD_INS (bblock, cmp);
12096                                 ins->type = STACK_I4;
12097                                 ins->dreg = alloc_dreg (cfg, ins->type);
12098                                 type_from_op (ins, sp [0], sp [1]);
12099
12100                                 if (cmp->opcode == OP_FCOMPARE) {
12101                                         /*
12102                                          * The backends expect the fceq opcodes to do the
12103                                          * comparison too.
12104                                          */
12105                                         ins->sreg1 = cmp->sreg1;
12106                                         ins->sreg2 = cmp->sreg2;
12107                                         NULLIFY_INS (cmp);
12108                                 }
12109                                 MONO_ADD_INS (bblock, ins);
12110                                 *sp++ = ins;
12111                                 ip += 2;
12112                                 break;
12113                         }
12114                         case CEE_LDFTN: {
12115                                 MonoInst *argconst;
12116                                 MonoMethod *cil_method;
12117
12118                                 CHECK_STACK_OVF (1);
12119                                 CHECK_OPSIZE (6);
12120                                 n = read32 (ip + 2);
12121                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12122                                 if (!cmethod || mono_loader_get_last_error ())
12123                                         LOAD_ERROR;
12124                                 mono_class_init (cmethod->klass);
12125
12126                                 mono_save_token_info (cfg, image, n, cmethod);
12127
12128                                 context_used = mini_method_check_context_used (cfg, cmethod);
12129
12130                                 cil_method = cmethod;
12131                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12132                                         METHOD_ACCESS_FAILURE (method, cil_method);
12133
12134                                 if (mono_security_cas_enabled ()) {
12135                                         if (check_linkdemand (cfg, method, cmethod))
12136                                                 INLINE_FAILURE ("linkdemand");
12137                                         CHECK_CFG_EXCEPTION;
12138                                 } else if (mono_security_core_clr_enabled ()) {
12139                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12140                                 }
12141
12142                                 /* 
12143                                  * Optimize the common case of ldftn+delegate creation
12144                                  */
12145                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12146                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12147                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12148                                                 MonoInst *target_ins, *handle_ins;
12149                                                 MonoMethod *invoke;
12150                                                 int invoke_context_used;
12151
12152                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12153                                                 if (!invoke || !mono_method_signature (invoke))
12154                                                         LOAD_ERROR;
12155
12156                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12157
12158                                                 target_ins = sp [-1];
12159
12160                                                 if (mono_security_core_clr_enabled ())
12161                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12162
12163                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12164                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12165                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12166                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12167                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12168                                                         }
12169                                                 }
12170
12171 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12172                                                 /* FIXME: SGEN support */
12173                                                 if (invoke_context_used == 0) {
12174                                                         ip += 6;
12175                                                         if (cfg->verbose_level > 3)
12176                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12177                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12178                                                                 sp --;
12179                                                                 *sp = handle_ins;
12180                                                                 CHECK_CFG_EXCEPTION;
12181                                                                 ip += 5;
12182                                                                 sp ++;
12183                                                                 break;
12184                                                         }
12185                                                         ip -= 6;
12186                                                 }
12187 #endif
12188                                         }
12189                                 }
12190
12191                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12192                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12193                                 *sp++ = ins;
12194                                 
12195                                 ip += 6;
12196                                 inline_costs += 10 * num_calls++;
12197                                 break;
12198                         }
12199                         case CEE_LDVIRTFTN: {
12200                                 MonoInst *args [2];
12201
12202                                 CHECK_STACK (1);
12203                                 CHECK_OPSIZE (6);
12204                                 n = read32 (ip + 2);
12205                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12206                                 if (!cmethod || mono_loader_get_last_error ())
12207                                         LOAD_ERROR;
12208                                 mono_class_init (cmethod->klass);
12209  
12210                                 context_used = mini_method_check_context_used (cfg, cmethod);
12211
12212                                 if (mono_security_cas_enabled ()) {
12213                                         if (check_linkdemand (cfg, method, cmethod))
12214                                                 INLINE_FAILURE ("linkdemand");
12215                                         CHECK_CFG_EXCEPTION;
12216                                 } else if (mono_security_core_clr_enabled ()) {
12217                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
12218                                 }
12219
12220                                 /*
12221                                  * Optimize the common case of ldvirtftn+delegate creation
12222                                  */
12223                                 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)) {
12224                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12225                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12226                                                 MonoInst *target_ins, *handle_ins;
12227                                                 MonoMethod *invoke;
12228                                                 int invoke_context_used;
12229
12230                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12231                                                 if (!invoke || !mono_method_signature (invoke))
12232                                                         LOAD_ERROR;
12233
12234                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12235
12236                                                 target_ins = sp [-1];
12237
12238                                                 if (mono_security_core_clr_enabled ())
12239                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
12240
12241 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
12242                                                 /* FIXME: SGEN support */
12243                                                 if (invoke_context_used == 0) {
12244                                                         ip += 6;
12245                                                         if (cfg->verbose_level > 3)
12246                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12247                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, TRUE))) {
12248                                                                 sp -= 2;
12249                                                                 *sp = handle_ins;
12250                                                                 CHECK_CFG_EXCEPTION;
12251                                                                 ip += 5;
12252                                                                 sp ++;
12253                                                                 break;
12254                                                         }
12255                                                         ip -= 6;
12256                                                 }
12257 #endif
12258                                         }
12259                                 }
12260
12261                                 --sp;
12262                                 args [0] = *sp;
12263
12264                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12265                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12266
12267                                 if (context_used)
12268                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12269                                 else
12270                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12271
12272                                 ip += 6;
12273                                 inline_costs += 10 * num_calls++;
12274                                 break;
12275                         }
12276                         case CEE_LDARG:
12277                                 CHECK_STACK_OVF (1);
12278                                 CHECK_OPSIZE (4);
12279                                 n = read16 (ip + 2);
12280                                 CHECK_ARG (n);
12281                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12282                                 *sp++ = ins;
12283                                 ip += 4;
12284                                 break;
12285                         case CEE_LDARGA:
12286                                 CHECK_STACK_OVF (1);
12287                                 CHECK_OPSIZE (4);
12288                                 n = read16 (ip + 2);
12289                                 CHECK_ARG (n);
12290                                 NEW_ARGLOADA (cfg, ins, n);
12291                                 MONO_ADD_INS (cfg->cbb, ins);
12292                                 *sp++ = ins;
12293                                 ip += 4;
12294                                 break;
12295                         case CEE_STARG:
12296                                 CHECK_STACK (1);
12297                                 --sp;
12298                                 CHECK_OPSIZE (4);
12299                                 n = read16 (ip + 2);
12300                                 CHECK_ARG (n);
12301                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12302                                         UNVERIFIED;
12303                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12304                                 ip += 4;
12305                                 break;
12306                         case CEE_LDLOC:
12307                                 CHECK_STACK_OVF (1);
12308                                 CHECK_OPSIZE (4);
12309                                 n = read16 (ip + 2);
12310                                 CHECK_LOCAL (n);
12311                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12312                                 *sp++ = ins;
12313                                 ip += 4;
12314                                 break;
12315                         case CEE_LDLOCA: {
12316                                 unsigned char *tmp_ip;
12317                                 CHECK_STACK_OVF (1);
12318                                 CHECK_OPSIZE (4);
12319                                 n = read16 (ip + 2);
12320                                 CHECK_LOCAL (n);
12321
12322                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12323                                         ip = tmp_ip;
12324                                         inline_costs += 1;
12325                                         break;
12326                                 }                       
12327                                 
12328                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12329                                 *sp++ = ins;
12330                                 ip += 4;
12331                                 break;
12332                         }
12333                         case CEE_STLOC:
12334                                 CHECK_STACK (1);
12335                                 --sp;
12336                                 CHECK_OPSIZE (4);
12337                                 n = read16 (ip + 2);
12338                                 CHECK_LOCAL (n);
12339                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12340                                         UNVERIFIED;
12341                                 emit_stloc_ir (cfg, sp, header, n);
12342                                 ip += 4;
12343                                 inline_costs += 1;
12344                                 break;
12345                         case CEE_LOCALLOC:
12346                                 CHECK_STACK (1);
12347                                 --sp;
12348                                 if (sp != stack_start) 
12349                                         UNVERIFIED;
12350                                 if (cfg->method != method) 
12351                                         /* 
12352                                          * Inlining this into a loop in a parent could lead to 
12353                                          * stack overflows which is different behavior than the
12354                                          * non-inlined case, thus disable inlining in this case.
12355                                          */
12356                                         INLINE_FAILURE("localloc");
12357
12358                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12359                                 ins->dreg = alloc_preg (cfg);
12360                                 ins->sreg1 = sp [0]->dreg;
12361                                 ins->type = STACK_PTR;
12362                                 MONO_ADD_INS (cfg->cbb, ins);
12363
12364                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12365                                 if (init_locals)
12366                                         ins->flags |= MONO_INST_INIT;
12367
12368                                 *sp++ = ins;
12369                                 ip += 2;
12370                                 break;
12371                         case CEE_ENDFILTER: {
12372                                 MonoExceptionClause *clause, *nearest;
12373                                 int cc, nearest_num;
12374
12375                                 CHECK_STACK (1);
12376                                 --sp;
12377                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12378                                         UNVERIFIED;
12379                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12380                                 ins->sreg1 = (*sp)->dreg;
12381                                 MONO_ADD_INS (bblock, ins);
12382                                 start_new_bblock = 1;
12383                                 ip += 2;
12384
12385                                 nearest = NULL;
12386                                 nearest_num = 0;
12387                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12388                                         clause = &header->clauses [cc];
12389                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12390                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12391                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
12392                                                 nearest = clause;
12393                                                 nearest_num = cc;
12394                                         }
12395                                 }
12396                                 g_assert (nearest);
12397                                 if ((ip - header->code) != nearest->handler_offset)
12398                                         UNVERIFIED;
12399
12400                                 break;
12401                         }
12402                         case CEE_UNALIGNED_:
12403                                 ins_flag |= MONO_INST_UNALIGNED;
12404                                 /* FIXME: record alignment? we can assume 1 for now */
12405                                 CHECK_OPSIZE (3);
12406                                 ip += 3;
12407                                 break;
12408                         case CEE_VOLATILE_:
12409                                 ins_flag |= MONO_INST_VOLATILE;
12410                                 ip += 2;
12411                                 break;
12412                         case CEE_TAIL_:
12413                                 ins_flag   |= MONO_INST_TAILCALL;
12414                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12415                                 /* Can't inline tail calls at this time */
12416                                 inline_costs += 100000;
12417                                 ip += 2;
12418                                 break;
12419                         case CEE_INITOBJ:
12420                                 CHECK_STACK (1);
12421                                 --sp;
12422                                 CHECK_OPSIZE (6);
12423                                 token = read32 (ip + 2);
12424                                 klass = mini_get_class (method, token, generic_context);
12425                                 CHECK_TYPELOAD (klass);
12426                                 if (generic_class_is_reference_type (cfg, klass))
12427                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12428                                 else
12429                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12430                                 ip += 6;
12431                                 inline_costs += 1;
12432                                 break;
12433                         case CEE_CONSTRAINED_:
12434                                 CHECK_OPSIZE (6);
12435                                 token = read32 (ip + 2);
12436                                 constrained_call = mini_get_class (method, token, generic_context);
12437                                 CHECK_TYPELOAD (constrained_call);
12438                                 ip += 6;
12439                                 break;
12440                         case CEE_CPBLK:
12441                         case CEE_INITBLK: {
12442                                 MonoInst *iargs [3];
12443                                 CHECK_STACK (3);
12444                                 sp -= 3;
12445
12446                                 /* Skip optimized paths for volatile operations. */
12447                                 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)) {
12448                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12449                                 } 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)) {
12450                                         /* emit_memset only works when val == 0 */
12451                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12452                                 } else {
12453                                         MonoInst *call;
12454                                         iargs [0] = sp [0];
12455                                         iargs [1] = sp [1];
12456                                         iargs [2] = sp [2];
12457                                         if (ip [1] == CEE_CPBLK) {
12458                                                 /*
12459                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12460                                                  * and release barriers for cpblk. It is technically both a load and
12461                                                  * store operation, so it seems like that's the sensible thing to do.
12462                                                  *
12463                                                  * FIXME: We emit full barriers on both sides of the operation for
12464                                                  * simplicity. We should have a separate atomic memcpy method instead.
12465                                                  */
12466                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12467
12468                                                 if (ins_flag & MONO_INST_VOLATILE)
12469                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12470
12471                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12472                                                 call->flags |= ins_flag;
12473
12474                                                 if (ins_flag & MONO_INST_VOLATILE)
12475                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12476                                         } else {
12477                                                 MonoMethod *memset_method = get_memset_method ();
12478                                                 if (ins_flag & MONO_INST_VOLATILE) {
12479                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12480                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12481                                                 }
12482                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12483                                                 call->flags |= ins_flag;
12484                                         }
12485                                 }
12486                                 ip += 2;
12487                                 ins_flag = 0;
12488                                 inline_costs += 1;
12489                                 break;
12490                         }
12491                         case CEE_NO_:
12492                                 CHECK_OPSIZE (3);
12493                                 if (ip [2] & 0x1)
12494                                         ins_flag |= MONO_INST_NOTYPECHECK;
12495                                 if (ip [2] & 0x2)
12496                                         ins_flag |= MONO_INST_NORANGECHECK;
12497                                 /* we ignore the no-nullcheck for now since we
12498                                  * really do it explicitly only when doing callvirt->call
12499                                  */
12500                                 ip += 3;
12501                                 break;
12502                         case CEE_RETHROW: {
12503                                 MonoInst *load;
12504                                 int handler_offset = -1;
12505
12506                                 for (i = 0; i < header->num_clauses; ++i) {
12507                                         MonoExceptionClause *clause = &header->clauses [i];
12508                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
12509                                                 handler_offset = clause->handler_offset;
12510                                                 break;
12511                                         }
12512                                 }
12513
12514                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
12515
12516                                 if (handler_offset == -1)
12517                                         UNVERIFIED;
12518
12519                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
12520                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
12521                                 ins->sreg1 = load->dreg;
12522                                 MONO_ADD_INS (bblock, ins);
12523
12524                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12525                                 MONO_ADD_INS (bblock, ins);
12526
12527                                 sp = stack_start;
12528                                 link_bblock (cfg, bblock, end_bblock);
12529                                 start_new_bblock = 1;
12530                                 ip += 2;
12531                                 break;
12532                         }
12533                         case CEE_SIZEOF: {
12534                                 guint32 val;
12535                                 int ialign;
12536
12537                                 CHECK_STACK_OVF (1);
12538                                 CHECK_OPSIZE (6);
12539                                 token = read32 (ip + 2);
12540                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
12541                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
12542                                         CHECK_CFG_ERROR;
12543
12544                                         val = mono_type_size (type, &ialign);
12545                                 } else {
12546                                         MonoClass *klass = mini_get_class (method, token, generic_context);
12547                                         CHECK_TYPELOAD (klass);
12548
12549                                         val = mono_type_size (&klass->byval_arg, &ialign);
12550
12551                                         if (mini_is_gsharedvt_klass (cfg, klass))
12552                                                 GSHAREDVT_FAILURE (*ip);
12553                                 }
12554                                 EMIT_NEW_ICONST (cfg, ins, val);
12555                                 *sp++= ins;
12556                                 ip += 6;
12557                                 break;
12558                         }
12559                         case CEE_REFANYTYPE: {
12560                                 MonoInst *src_var, *src;
12561
12562                                 GSHAREDVT_FAILURE (*ip);
12563
12564                                 CHECK_STACK (1);
12565                                 --sp;
12566
12567                                 // FIXME:
12568                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12569                                 if (!src_var)
12570                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
12571                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
12572                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
12573                                 *sp++ = ins;
12574                                 ip += 2;
12575                                 break;
12576                         }
12577                         case CEE_READONLY_:
12578                                 readonly = TRUE;
12579                                 ip += 2;
12580                                 break;
12581
12582                         case CEE_UNUSED56:
12583                         case CEE_UNUSED57:
12584                         case CEE_UNUSED70:
12585                         case CEE_UNUSED:
12586                         case CEE_UNUSED99:
12587                                 UNVERIFIED;
12588                                 
12589                         default:
12590                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
12591                                 UNVERIFIED;
12592                         }
12593                         break;
12594                 }
12595                 case CEE_UNUSED58:
12596                 case CEE_UNUSED1:
12597                         UNVERIFIED;
12598
12599                 default:
12600                         g_warning ("opcode 0x%02x not handled", *ip);
12601                         UNVERIFIED;
12602                 }
12603         }
12604         if (start_new_bblock != 1)
12605                 UNVERIFIED;
12606
12607         bblock->cil_length = ip - bblock->cil_code;
12608         if (bblock->next_bb) {
12609                 /* This could already be set because of inlining, #693905 */
12610                 MonoBasicBlock *bb = bblock;
12611
12612                 while (bb->next_bb)
12613                         bb = bb->next_bb;
12614                 bb->next_bb = end_bblock;
12615         } else {
12616                 bblock->next_bb = end_bblock;
12617         }
12618
12619         if (cfg->method == method && cfg->domainvar) {
12620                 MonoInst *store;
12621                 MonoInst *get_domain;
12622
12623                 cfg->cbb = init_localsbb;
12624
12625                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
12626                         MONO_ADD_INS (cfg->cbb, get_domain);
12627                 } else {
12628                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
12629                 }
12630                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
12631                 MONO_ADD_INS (cfg->cbb, store);
12632         }
12633
12634 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
12635         if (cfg->compile_aot)
12636                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
12637                 mono_get_got_var (cfg);
12638 #endif
12639
12640         if (cfg->method == method && cfg->got_var)
12641                 mono_emit_load_got_addr (cfg);
12642
12643         if (init_localsbb) {
12644                 cfg->cbb = init_localsbb;
12645                 cfg->ip = NULL;
12646                 for (i = 0; i < header->num_locals; ++i) {
12647                         emit_init_local (cfg, i, header->locals [i], init_locals);
12648                 }
12649         }
12650
12651         if (cfg->init_ref_vars && cfg->method == method) {
12652                 /* Emit initialization for ref vars */
12653                 // FIXME: Avoid duplication initialization for IL locals.
12654                 for (i = 0; i < cfg->num_varinfo; ++i) {
12655                         MonoInst *ins = cfg->varinfo [i];
12656
12657                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
12658                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
12659                 }
12660         }
12661
12662         if (cfg->lmf_var && cfg->method == method) {
12663                 cfg->cbb = init_localsbb;
12664                 emit_push_lmf (cfg);
12665         }
12666
12667         cfg->cbb = init_localsbb;
12668         emit_instrumentation_call (cfg, mono_profiler_method_enter);
12669
12670         if (seq_points) {
12671                 MonoBasicBlock *bb;
12672
12673                 /*
12674                  * Make seq points at backward branch targets interruptable.
12675                  */
12676                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
12677                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
12678                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
12679         }
12680
12681         /* Add a sequence point for method entry/exit events */
12682         if (cfg->gen_seq_points_debug_data) {
12683                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
12684                 MONO_ADD_INS (init_localsbb, ins);
12685                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
12686                 MONO_ADD_INS (cfg->bb_exit, ins);
12687         }
12688
12689         /*
12690          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
12691          * the code they refer to was dead (#11880).
12692          */
12693         if (sym_seq_points) {
12694                 for (i = 0; i < header->code_size; ++i) {
12695                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
12696                                 MonoInst *ins;
12697
12698                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
12699                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
12700                         }
12701                 }
12702         }
12703
12704         cfg->ip = NULL;
12705
12706         if (cfg->method == method) {
12707                 MonoBasicBlock *bb;
12708                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12709                         bb->region = mono_find_block_region (cfg, bb->real_offset);
12710                         if (cfg->spvars)
12711                                 mono_create_spvar_for_region (cfg, bb->region);
12712                         if (cfg->verbose_level > 2)
12713                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
12714                 }
12715         }
12716
12717         if (inline_costs < 0) {
12718                 char *mname;
12719
12720                 /* Method is too large */
12721                 mname = mono_method_full_name (method, TRUE);
12722                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
12723                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
12724                 g_free (mname);
12725         }
12726
12727         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
12728                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
12729
12730         goto cleanup;
12731
12732 mono_error_exit:
12733         g_assert (!mono_error_ok (&cfg->error));
12734         goto cleanup;
12735  
12736  exception_exit:
12737         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
12738         goto cleanup;
12739
12740  unverified:
12741         set_exception_type_from_invalid_il (cfg, method, ip);
12742         goto cleanup;
12743
12744  cleanup:
12745         g_slist_free (class_inits);
12746         mono_basic_block_free (original_bb);
12747         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
12748         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
12749         if (cfg->exception_type)
12750                 return -1;
12751         else
12752                 return inline_costs;
12753 }
12754
12755 static int
12756 store_membase_reg_to_store_membase_imm (int opcode)
12757 {
12758         switch (opcode) {
12759         case OP_STORE_MEMBASE_REG:
12760                 return OP_STORE_MEMBASE_IMM;
12761         case OP_STOREI1_MEMBASE_REG:
12762                 return OP_STOREI1_MEMBASE_IMM;
12763         case OP_STOREI2_MEMBASE_REG:
12764                 return OP_STOREI2_MEMBASE_IMM;
12765         case OP_STOREI4_MEMBASE_REG:
12766                 return OP_STOREI4_MEMBASE_IMM;
12767         case OP_STOREI8_MEMBASE_REG:
12768                 return OP_STOREI8_MEMBASE_IMM;
12769         default:
12770                 g_assert_not_reached ();
12771         }
12772
12773         return -1;
12774 }               
12775
12776 int
12777 mono_op_to_op_imm (int opcode)
12778 {
12779         switch (opcode) {
12780         case OP_IADD:
12781                 return OP_IADD_IMM;
12782         case OP_ISUB:
12783                 return OP_ISUB_IMM;
12784         case OP_IDIV:
12785                 return OP_IDIV_IMM;
12786         case OP_IDIV_UN:
12787                 return OP_IDIV_UN_IMM;
12788         case OP_IREM:
12789                 return OP_IREM_IMM;
12790         case OP_IREM_UN:
12791                 return OP_IREM_UN_IMM;
12792         case OP_IMUL:
12793                 return OP_IMUL_IMM;
12794         case OP_IAND:
12795                 return OP_IAND_IMM;
12796         case OP_IOR:
12797                 return OP_IOR_IMM;
12798         case OP_IXOR:
12799                 return OP_IXOR_IMM;
12800         case OP_ISHL:
12801                 return OP_ISHL_IMM;
12802         case OP_ISHR:
12803                 return OP_ISHR_IMM;
12804         case OP_ISHR_UN:
12805                 return OP_ISHR_UN_IMM;
12806
12807         case OP_LADD:
12808                 return OP_LADD_IMM;
12809         case OP_LSUB:
12810                 return OP_LSUB_IMM;
12811         case OP_LAND:
12812                 return OP_LAND_IMM;
12813         case OP_LOR:
12814                 return OP_LOR_IMM;
12815         case OP_LXOR:
12816                 return OP_LXOR_IMM;
12817         case OP_LSHL:
12818                 return OP_LSHL_IMM;
12819         case OP_LSHR:
12820                 return OP_LSHR_IMM;
12821         case OP_LSHR_UN:
12822                 return OP_LSHR_UN_IMM;
12823 #if SIZEOF_REGISTER == 8
12824         case OP_LREM:
12825                 return OP_LREM_IMM;
12826 #endif
12827
12828         case OP_COMPARE:
12829                 return OP_COMPARE_IMM;
12830         case OP_ICOMPARE:
12831                 return OP_ICOMPARE_IMM;
12832         case OP_LCOMPARE:
12833                 return OP_LCOMPARE_IMM;
12834
12835         case OP_STORE_MEMBASE_REG:
12836                 return OP_STORE_MEMBASE_IMM;
12837         case OP_STOREI1_MEMBASE_REG:
12838                 return OP_STOREI1_MEMBASE_IMM;
12839         case OP_STOREI2_MEMBASE_REG:
12840                 return OP_STOREI2_MEMBASE_IMM;
12841         case OP_STOREI4_MEMBASE_REG:
12842                 return OP_STOREI4_MEMBASE_IMM;
12843
12844 #if defined(TARGET_X86) || defined (TARGET_AMD64)
12845         case OP_X86_PUSH:
12846                 return OP_X86_PUSH_IMM;
12847         case OP_X86_COMPARE_MEMBASE_REG:
12848                 return OP_X86_COMPARE_MEMBASE_IMM;
12849 #endif
12850 #if defined(TARGET_AMD64)
12851         case OP_AMD64_ICOMPARE_MEMBASE_REG:
12852                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12853 #endif
12854         case OP_VOIDCALL_REG:
12855                 return OP_VOIDCALL;
12856         case OP_CALL_REG:
12857                 return OP_CALL;
12858         case OP_LCALL_REG:
12859                 return OP_LCALL;
12860         case OP_FCALL_REG:
12861                 return OP_FCALL;
12862         case OP_LOCALLOC:
12863                 return OP_LOCALLOC_IMM;
12864         }
12865
12866         return -1;
12867 }
12868
12869 static int
12870 ldind_to_load_membase (int opcode)
12871 {
12872         switch (opcode) {
12873         case CEE_LDIND_I1:
12874                 return OP_LOADI1_MEMBASE;
12875         case CEE_LDIND_U1:
12876                 return OP_LOADU1_MEMBASE;
12877         case CEE_LDIND_I2:
12878                 return OP_LOADI2_MEMBASE;
12879         case CEE_LDIND_U2:
12880                 return OP_LOADU2_MEMBASE;
12881         case CEE_LDIND_I4:
12882                 return OP_LOADI4_MEMBASE;
12883         case CEE_LDIND_U4:
12884                 return OP_LOADU4_MEMBASE;
12885         case CEE_LDIND_I:
12886                 return OP_LOAD_MEMBASE;
12887         case CEE_LDIND_REF:
12888                 return OP_LOAD_MEMBASE;
12889         case CEE_LDIND_I8:
12890                 return OP_LOADI8_MEMBASE;
12891         case CEE_LDIND_R4:
12892                 return OP_LOADR4_MEMBASE;
12893         case CEE_LDIND_R8:
12894                 return OP_LOADR8_MEMBASE;
12895         default:
12896                 g_assert_not_reached ();
12897         }
12898
12899         return -1;
12900 }
12901
12902 static int
12903 stind_to_store_membase (int opcode)
12904 {
12905         switch (opcode) {
12906         case CEE_STIND_I1:
12907                 return OP_STOREI1_MEMBASE_REG;
12908         case CEE_STIND_I2:
12909                 return OP_STOREI2_MEMBASE_REG;
12910         case CEE_STIND_I4:
12911                 return OP_STOREI4_MEMBASE_REG;
12912         case CEE_STIND_I:
12913         case CEE_STIND_REF:
12914                 return OP_STORE_MEMBASE_REG;
12915         case CEE_STIND_I8:
12916                 return OP_STOREI8_MEMBASE_REG;
12917         case CEE_STIND_R4:
12918                 return OP_STORER4_MEMBASE_REG;
12919         case CEE_STIND_R8:
12920                 return OP_STORER8_MEMBASE_REG;
12921         default:
12922                 g_assert_not_reached ();
12923         }
12924
12925         return -1;
12926 }
12927
12928 int
12929 mono_load_membase_to_load_mem (int opcode)
12930 {
12931         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12932 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12933         switch (opcode) {
12934         case OP_LOAD_MEMBASE:
12935                 return OP_LOAD_MEM;
12936         case OP_LOADU1_MEMBASE:
12937                 return OP_LOADU1_MEM;
12938         case OP_LOADU2_MEMBASE:
12939                 return OP_LOADU2_MEM;
12940         case OP_LOADI4_MEMBASE:
12941                 return OP_LOADI4_MEM;
12942         case OP_LOADU4_MEMBASE:
12943                 return OP_LOADU4_MEM;
12944 #if SIZEOF_REGISTER == 8
12945         case OP_LOADI8_MEMBASE:
12946                 return OP_LOADI8_MEM;
12947 #endif
12948         }
12949 #endif
12950
12951         return -1;
12952 }
12953
12954 static inline int
12955 op_to_op_dest_membase (int store_opcode, int opcode)
12956 {
12957 #if defined(TARGET_X86)
12958         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12959                 return -1;
12960
12961         switch (opcode) {
12962         case OP_IADD:
12963                 return OP_X86_ADD_MEMBASE_REG;
12964         case OP_ISUB:
12965                 return OP_X86_SUB_MEMBASE_REG;
12966         case OP_IAND:
12967                 return OP_X86_AND_MEMBASE_REG;
12968         case OP_IOR:
12969                 return OP_X86_OR_MEMBASE_REG;
12970         case OP_IXOR:
12971                 return OP_X86_XOR_MEMBASE_REG;
12972         case OP_ADD_IMM:
12973         case OP_IADD_IMM:
12974                 return OP_X86_ADD_MEMBASE_IMM;
12975         case OP_SUB_IMM:
12976         case OP_ISUB_IMM:
12977                 return OP_X86_SUB_MEMBASE_IMM;
12978         case OP_AND_IMM:
12979         case OP_IAND_IMM:
12980                 return OP_X86_AND_MEMBASE_IMM;
12981         case OP_OR_IMM:
12982         case OP_IOR_IMM:
12983                 return OP_X86_OR_MEMBASE_IMM;
12984         case OP_XOR_IMM:
12985         case OP_IXOR_IMM:
12986                 return OP_X86_XOR_MEMBASE_IMM;
12987         case OP_MOVE:
12988                 return OP_NOP;
12989         }
12990 #endif
12991
12992 #if defined(TARGET_AMD64)
12993         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12994                 return -1;
12995
12996         switch (opcode) {
12997         case OP_IADD:
12998                 return OP_X86_ADD_MEMBASE_REG;
12999         case OP_ISUB:
13000                 return OP_X86_SUB_MEMBASE_REG;
13001         case OP_IAND:
13002                 return OP_X86_AND_MEMBASE_REG;
13003         case OP_IOR:
13004                 return OP_X86_OR_MEMBASE_REG;
13005         case OP_IXOR:
13006                 return OP_X86_XOR_MEMBASE_REG;
13007         case OP_IADD_IMM:
13008                 return OP_X86_ADD_MEMBASE_IMM;
13009         case OP_ISUB_IMM:
13010                 return OP_X86_SUB_MEMBASE_IMM;
13011         case OP_IAND_IMM:
13012                 return OP_X86_AND_MEMBASE_IMM;
13013         case OP_IOR_IMM:
13014                 return OP_X86_OR_MEMBASE_IMM;
13015         case OP_IXOR_IMM:
13016                 return OP_X86_XOR_MEMBASE_IMM;
13017         case OP_LADD:
13018                 return OP_AMD64_ADD_MEMBASE_REG;
13019         case OP_LSUB:
13020                 return OP_AMD64_SUB_MEMBASE_REG;
13021         case OP_LAND:
13022                 return OP_AMD64_AND_MEMBASE_REG;
13023         case OP_LOR:
13024                 return OP_AMD64_OR_MEMBASE_REG;
13025         case OP_LXOR:
13026                 return OP_AMD64_XOR_MEMBASE_REG;
13027         case OP_ADD_IMM:
13028         case OP_LADD_IMM:
13029                 return OP_AMD64_ADD_MEMBASE_IMM;
13030         case OP_SUB_IMM:
13031         case OP_LSUB_IMM:
13032                 return OP_AMD64_SUB_MEMBASE_IMM;
13033         case OP_AND_IMM:
13034         case OP_LAND_IMM:
13035                 return OP_AMD64_AND_MEMBASE_IMM;
13036         case OP_OR_IMM:
13037         case OP_LOR_IMM:
13038                 return OP_AMD64_OR_MEMBASE_IMM;
13039         case OP_XOR_IMM:
13040         case OP_LXOR_IMM:
13041                 return OP_AMD64_XOR_MEMBASE_IMM;
13042         case OP_MOVE:
13043                 return OP_NOP;
13044         }
13045 #endif
13046
13047         return -1;
13048 }
13049
13050 static inline int
13051 op_to_op_store_membase (int store_opcode, int opcode)
13052 {
13053 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13054         switch (opcode) {
13055         case OP_ICEQ:
13056                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13057                         return OP_X86_SETEQ_MEMBASE;
13058         case OP_CNE:
13059                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13060                         return OP_X86_SETNE_MEMBASE;
13061         }
13062 #endif
13063
13064         return -1;
13065 }
13066
13067 static inline int
13068 op_to_op_src1_membase (int load_opcode, int opcode)
13069 {
13070 #ifdef TARGET_X86
13071         /* FIXME: This has sign extension issues */
13072         /*
13073         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13074                 return OP_X86_COMPARE_MEMBASE8_IMM;
13075         */
13076
13077         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13078                 return -1;
13079
13080         switch (opcode) {
13081         case OP_X86_PUSH:
13082                 return OP_X86_PUSH_MEMBASE;
13083         case OP_COMPARE_IMM:
13084         case OP_ICOMPARE_IMM:
13085                 return OP_X86_COMPARE_MEMBASE_IMM;
13086         case OP_COMPARE:
13087         case OP_ICOMPARE:
13088                 return OP_X86_COMPARE_MEMBASE_REG;
13089         }
13090 #endif
13091
13092 #ifdef TARGET_AMD64
13093         /* FIXME: This has sign extension issues */
13094         /*
13095         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13096                 return OP_X86_COMPARE_MEMBASE8_IMM;
13097         */
13098
13099         switch (opcode) {
13100         case OP_X86_PUSH:
13101 #ifdef __mono_ilp32__
13102                 if (load_opcode == OP_LOADI8_MEMBASE)
13103 #else
13104                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13105 #endif
13106                         return OP_X86_PUSH_MEMBASE;
13107                 break;
13108                 /* FIXME: This only works for 32 bit immediates
13109         case OP_COMPARE_IMM:
13110         case OP_LCOMPARE_IMM:
13111                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13112                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13113                 */
13114         case OP_ICOMPARE_IMM:
13115                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13116                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13117                 break;
13118         case OP_COMPARE:
13119         case OP_LCOMPARE:
13120 #ifdef __mono_ilp32__
13121                 if (load_opcode == OP_LOAD_MEMBASE)
13122                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13123                 if (load_opcode == OP_LOADI8_MEMBASE)
13124 #else
13125                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13126 #endif
13127                         return OP_AMD64_COMPARE_MEMBASE_REG;
13128                 break;
13129         case OP_ICOMPARE:
13130                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13131                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13132                 break;
13133         }
13134 #endif
13135
13136         return -1;
13137 }
13138
13139 static inline int
13140 op_to_op_src2_membase (int load_opcode, int opcode)
13141 {
13142 #ifdef TARGET_X86
13143         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13144                 return -1;
13145         
13146         switch (opcode) {
13147         case OP_COMPARE:
13148         case OP_ICOMPARE:
13149                 return OP_X86_COMPARE_REG_MEMBASE;
13150         case OP_IADD:
13151                 return OP_X86_ADD_REG_MEMBASE;
13152         case OP_ISUB:
13153                 return OP_X86_SUB_REG_MEMBASE;
13154         case OP_IAND:
13155                 return OP_X86_AND_REG_MEMBASE;
13156         case OP_IOR:
13157                 return OP_X86_OR_REG_MEMBASE;
13158         case OP_IXOR:
13159                 return OP_X86_XOR_REG_MEMBASE;
13160         }
13161 #endif
13162
13163 #ifdef TARGET_AMD64
13164 #ifdef __mono_ilp32__
13165         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
13166 #else
13167         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
13168 #endif
13169                 switch (opcode) {
13170                 case OP_ICOMPARE:
13171                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13172                 case OP_IADD:
13173                         return OP_X86_ADD_REG_MEMBASE;
13174                 case OP_ISUB:
13175                         return OP_X86_SUB_REG_MEMBASE;
13176                 case OP_IAND:
13177                         return OP_X86_AND_REG_MEMBASE;
13178                 case OP_IOR:
13179                         return OP_X86_OR_REG_MEMBASE;
13180                 case OP_IXOR:
13181                         return OP_X86_XOR_REG_MEMBASE;
13182                 }
13183 #ifdef __mono_ilp32__
13184         } else if (load_opcode == OP_LOADI8_MEMBASE) {
13185 #else
13186         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
13187 #endif
13188                 switch (opcode) {
13189                 case OP_COMPARE:
13190                 case OP_LCOMPARE:
13191                         return OP_AMD64_COMPARE_REG_MEMBASE;
13192                 case OP_LADD:
13193                         return OP_AMD64_ADD_REG_MEMBASE;
13194                 case OP_LSUB:
13195                         return OP_AMD64_SUB_REG_MEMBASE;
13196                 case OP_LAND:
13197                         return OP_AMD64_AND_REG_MEMBASE;
13198                 case OP_LOR:
13199                         return OP_AMD64_OR_REG_MEMBASE;
13200                 case OP_LXOR:
13201                         return OP_AMD64_XOR_REG_MEMBASE;
13202                 }
13203         }
13204 #endif
13205
13206         return -1;
13207 }
13208
13209 int
13210 mono_op_to_op_imm_noemul (int opcode)
13211 {
13212         switch (opcode) {
13213 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13214         case OP_LSHR:
13215         case OP_LSHL:
13216         case OP_LSHR_UN:
13217                 return -1;
13218 #endif
13219 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13220         case OP_IDIV:
13221         case OP_IDIV_UN:
13222         case OP_IREM:
13223         case OP_IREM_UN:
13224                 return -1;
13225 #endif
13226 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13227         case OP_IMUL:
13228                 return -1;
13229 #endif
13230         default:
13231                 return mono_op_to_op_imm (opcode);
13232         }
13233 }
13234
13235 /**
13236  * mono_handle_global_vregs:
13237  *
13238  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13239  * for them.
13240  */
13241 void
13242 mono_handle_global_vregs (MonoCompile *cfg)
13243 {
13244         gint32 *vreg_to_bb;
13245         MonoBasicBlock *bb;
13246         int i, pos;
13247
13248         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13249
13250 #ifdef MONO_ARCH_SIMD_INTRINSICS
13251         if (cfg->uses_simd_intrinsics)
13252                 mono_simd_simplify_indirection (cfg);
13253 #endif
13254
13255         /* Find local vregs used in more than one bb */
13256         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13257                 MonoInst *ins = bb->code;       
13258                 int block_num = bb->block_num;
13259
13260                 if (cfg->verbose_level > 2)
13261                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13262
13263                 cfg->cbb = bb;
13264                 for (; ins; ins = ins->next) {
13265                         const char *spec = INS_INFO (ins->opcode);
13266                         int regtype = 0, regindex;
13267                         gint32 prev_bb;
13268
13269                         if (G_UNLIKELY (cfg->verbose_level > 2))
13270                                 mono_print_ins (ins);
13271
13272                         g_assert (ins->opcode >= MONO_CEE_LAST);
13273
13274                         for (regindex = 0; regindex < 4; regindex ++) {
13275                                 int vreg = 0;
13276
13277                                 if (regindex == 0) {
13278                                         regtype = spec [MONO_INST_DEST];
13279                                         if (regtype == ' ')
13280                                                 continue;
13281                                         vreg = ins->dreg;
13282                                 } else if (regindex == 1) {
13283                                         regtype = spec [MONO_INST_SRC1];
13284                                         if (regtype == ' ')
13285                                                 continue;
13286                                         vreg = ins->sreg1;
13287                                 } else if (regindex == 2) {
13288                                         regtype = spec [MONO_INST_SRC2];
13289                                         if (regtype == ' ')
13290                                                 continue;
13291                                         vreg = ins->sreg2;
13292                                 } else if (regindex == 3) {
13293                                         regtype = spec [MONO_INST_SRC3];
13294                                         if (regtype == ' ')
13295                                                 continue;
13296                                         vreg = ins->sreg3;
13297                                 }
13298
13299 #if SIZEOF_REGISTER == 4
13300                                 /* In the LLVM case, the long opcodes are not decomposed */
13301                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13302                                         /*
13303                                          * Since some instructions reference the original long vreg,
13304                                          * and some reference the two component vregs, it is quite hard
13305                                          * to determine when it needs to be global. So be conservative.
13306                                          */
13307                                         if (!get_vreg_to_inst (cfg, vreg)) {
13308                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13309
13310                                                 if (cfg->verbose_level > 2)
13311                                                         printf ("LONG VREG R%d made global.\n", vreg);
13312                                         }
13313
13314                                         /*
13315                                          * Make the component vregs volatile since the optimizations can
13316                                          * get confused otherwise.
13317                                          */
13318                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13319                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13320                                 }
13321 #endif
13322
13323                                 g_assert (vreg != -1);
13324
13325                                 prev_bb = vreg_to_bb [vreg];
13326                                 if (prev_bb == 0) {
13327                                         /* 0 is a valid block num */
13328                                         vreg_to_bb [vreg] = block_num + 1;
13329                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13330                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13331                                                 continue;
13332
13333                                         if (!get_vreg_to_inst (cfg, vreg)) {
13334                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13335                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13336
13337                                                 switch (regtype) {
13338                                                 case 'i':
13339                                                         if (vreg_is_ref (cfg, vreg))
13340                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13341                                                         else
13342                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13343                                                         break;
13344                                                 case 'l':
13345                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13346                                                         break;
13347                                                 case 'f':
13348                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13349                                                         break;
13350                                                 case 'v':
13351                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13352                                                         break;
13353                                                 default:
13354                                                         g_assert_not_reached ();
13355                                                 }
13356                                         }
13357
13358                                         /* Flag as having been used in more than one bb */
13359                                         vreg_to_bb [vreg] = -1;
13360                                 }
13361                         }
13362                 }
13363         }
13364
13365         /* If a variable is used in only one bblock, convert it into a local vreg */
13366         for (i = 0; i < cfg->num_varinfo; i++) {
13367                 MonoInst *var = cfg->varinfo [i];
13368                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13369
13370                 switch (var->type) {
13371                 case STACK_I4:
13372                 case STACK_OBJ:
13373                 case STACK_PTR:
13374                 case STACK_MP:
13375                 case STACK_VTYPE:
13376 #if SIZEOF_REGISTER == 8
13377                 case STACK_I8:
13378 #endif
13379 #if !defined(TARGET_X86)
13380                 /* Enabling this screws up the fp stack on x86 */
13381                 case STACK_R8:
13382 #endif
13383                         if (mono_arch_is_soft_float ())
13384                                 break;
13385
13386                         /* Arguments are implicitly global */
13387                         /* Putting R4 vars into registers doesn't work currently */
13388                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13389                         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) {
13390                                 /* 
13391                                  * Make that the variable's liveness interval doesn't contain a call, since
13392                                  * that would cause the lvreg to be spilled, making the whole optimization
13393                                  * useless.
13394                                  */
13395                                 /* This is too slow for JIT compilation */
13396 #if 0
13397                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13398                                         MonoInst *ins;
13399                                         int def_index, call_index, ins_index;
13400                                         gboolean spilled = FALSE;
13401
13402                                         def_index = -1;
13403                                         call_index = -1;
13404                                         ins_index = 0;
13405                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13406                                                 const char *spec = INS_INFO (ins->opcode);
13407
13408                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13409                                                         def_index = ins_index;
13410
13411                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13412                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13413                                                         if (call_index > def_index) {
13414                                                                 spilled = TRUE;
13415                                                                 break;
13416                                                         }
13417                                                 }
13418
13419                                                 if (MONO_IS_CALL (ins))
13420                                                         call_index = ins_index;
13421
13422                                                 ins_index ++;
13423                                         }
13424
13425                                         if (spilled)
13426                                                 break;
13427                                 }
13428 #endif
13429
13430                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13431                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13432                                 var->flags |= MONO_INST_IS_DEAD;
13433                                 cfg->vreg_to_inst [var->dreg] = NULL;
13434                         }
13435                         break;
13436                 }
13437         }
13438
13439         /* 
13440          * Compress the varinfo and vars tables so the liveness computation is faster and
13441          * takes up less space.
13442          */
13443         pos = 0;
13444         for (i = 0; i < cfg->num_varinfo; ++i) {
13445                 MonoInst *var = cfg->varinfo [i];
13446                 if (pos < i && cfg->locals_start == i)
13447                         cfg->locals_start = pos;
13448                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13449                         if (pos < i) {
13450                                 cfg->varinfo [pos] = cfg->varinfo [i];
13451                                 cfg->varinfo [pos]->inst_c0 = pos;
13452                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13453                                 cfg->vars [pos].idx = pos;
13454 #if SIZEOF_REGISTER == 4
13455                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13456                                         /* Modify the two component vars too */
13457                                         MonoInst *var1;
13458
13459                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13460                                         var1->inst_c0 = pos;
13461                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13462                                         var1->inst_c0 = pos;
13463                                 }
13464 #endif
13465                         }
13466                         pos ++;
13467                 }
13468         }
13469         cfg->num_varinfo = pos;
13470         if (cfg->locals_start > cfg->num_varinfo)
13471                 cfg->locals_start = cfg->num_varinfo;
13472 }
13473
13474 /**
13475  * mono_spill_global_vars:
13476  *
13477  *   Generate spill code for variables which are not allocated to registers, 
13478  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13479  * code is generated which could be optimized by the local optimization passes.
13480  */
13481 void
13482 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13483 {
13484         MonoBasicBlock *bb;
13485         char spec2 [16];
13486         int orig_next_vreg;
13487         guint32 *vreg_to_lvreg;
13488         guint32 *lvregs;
13489         guint32 i, lvregs_len;
13490         gboolean dest_has_lvreg = FALSE;
13491         guint32 stacktypes [128];
13492         MonoInst **live_range_start, **live_range_end;
13493         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13494         int *gsharedvt_vreg_to_idx = NULL;
13495
13496         *need_local_opts = FALSE;
13497
13498         memset (spec2, 0, sizeof (spec2));
13499
13500         /* FIXME: Move this function to mini.c */
13501         stacktypes ['i'] = STACK_PTR;
13502         stacktypes ['l'] = STACK_I8;
13503         stacktypes ['f'] = STACK_R8;
13504 #ifdef MONO_ARCH_SIMD_INTRINSICS
13505         stacktypes ['x'] = STACK_VTYPE;
13506 #endif
13507
13508 #if SIZEOF_REGISTER == 4
13509         /* Create MonoInsts for longs */
13510         for (i = 0; i < cfg->num_varinfo; i++) {
13511                 MonoInst *ins = cfg->varinfo [i];
13512
13513                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13514                         switch (ins->type) {
13515                         case STACK_R8:
13516                         case STACK_I8: {
13517                                 MonoInst *tree;
13518
13519                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13520                                         break;
13521
13522                                 g_assert (ins->opcode == OP_REGOFFSET);
13523
13524                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
13525                                 g_assert (tree);
13526                                 tree->opcode = OP_REGOFFSET;
13527                                 tree->inst_basereg = ins->inst_basereg;
13528                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
13529
13530                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
13531                                 g_assert (tree);
13532                                 tree->opcode = OP_REGOFFSET;
13533                                 tree->inst_basereg = ins->inst_basereg;
13534                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
13535                                 break;
13536                         }
13537                         default:
13538                                 break;
13539                         }
13540                 }
13541         }
13542 #endif
13543
13544         if (cfg->compute_gc_maps) {
13545                 /* registers need liveness info even for !non refs */
13546                 for (i = 0; i < cfg->num_varinfo; i++) {
13547                         MonoInst *ins = cfg->varinfo [i];
13548
13549                         if (ins->opcode == OP_REGVAR)
13550                                 ins->flags |= MONO_INST_GC_TRACK;
13551                 }
13552         }
13553
13554         if (cfg->gsharedvt) {
13555                 gsharedvt_vreg_to_idx = mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
13556
13557                 for (i = 0; i < cfg->num_varinfo; ++i) {
13558                         MonoInst *ins = cfg->varinfo [i];
13559                         int idx;
13560
13561                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
13562                                 if (i >= cfg->locals_start) {
13563                                         /* Local */
13564                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
13565                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
13566                                         ins->opcode = OP_GSHAREDVT_LOCAL;
13567                                         ins->inst_imm = idx;
13568                                 } else {
13569                                         /* Arg */
13570                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
13571                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
13572                                 }
13573                         }
13574                 }
13575         }
13576                 
13577         /* FIXME: widening and truncation */
13578
13579         /*
13580          * As an optimization, when a variable allocated to the stack is first loaded into 
13581          * an lvreg, we will remember the lvreg and use it the next time instead of loading
13582          * the variable again.
13583          */
13584         orig_next_vreg = cfg->next_vreg;
13585         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
13586         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
13587         lvregs_len = 0;
13588
13589         /* 
13590          * These arrays contain the first and last instructions accessing a given
13591          * variable.
13592          * Since we emit bblocks in the same order we process them here, and we
13593          * don't split live ranges, these will precisely describe the live range of
13594          * the variable, i.e. the instruction range where a valid value can be found
13595          * in the variables location.
13596          * The live range is computed using the liveness info computed by the liveness pass.
13597          * We can't use vmv->range, since that is an abstract live range, and we need
13598          * one which is instruction precise.
13599          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
13600          */
13601         /* FIXME: Only do this if debugging info is requested */
13602         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
13603         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
13604         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13605         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
13606         
13607         /* Add spill loads/stores */
13608         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13609                 MonoInst *ins;
13610
13611                 if (cfg->verbose_level > 2)
13612                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
13613
13614                 /* Clear vreg_to_lvreg array */
13615                 for (i = 0; i < lvregs_len; i++)
13616                         vreg_to_lvreg [lvregs [i]] = 0;
13617                 lvregs_len = 0;
13618
13619                 cfg->cbb = bb;
13620                 MONO_BB_FOR_EACH_INS (bb, ins) {
13621                         const char *spec = INS_INFO (ins->opcode);
13622                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
13623                         gboolean store, no_lvreg;
13624                         int sregs [MONO_MAX_SRC_REGS];
13625
13626                         if (G_UNLIKELY (cfg->verbose_level > 2))
13627                                 mono_print_ins (ins);
13628
13629                         if (ins->opcode == OP_NOP)
13630                                 continue;
13631
13632                         /* 
13633                          * We handle LDADDR here as well, since it can only be decomposed
13634                          * when variable addresses are known.
13635                          */
13636                         if (ins->opcode == OP_LDADDR) {
13637                                 MonoInst *var = ins->inst_p0;
13638
13639                                 if (var->opcode == OP_VTARG_ADDR) {
13640                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
13641                                         MonoInst *vtaddr = var->inst_left;
13642                                         if (vtaddr->opcode == OP_REGVAR) {
13643                                                 ins->opcode = OP_MOVE;
13644                                                 ins->sreg1 = vtaddr->dreg;
13645                                         }
13646                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
13647                                                 ins->opcode = OP_LOAD_MEMBASE;
13648                                                 ins->inst_basereg = vtaddr->inst_basereg;
13649                                                 ins->inst_offset = vtaddr->inst_offset;
13650                                         } else
13651                                                 NOT_IMPLEMENTED;
13652                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
13653                                         /* gsharedvt arg passed by ref */
13654                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
13655
13656                                         ins->opcode = OP_LOAD_MEMBASE;
13657                                         ins->inst_basereg = var->inst_basereg;
13658                                         ins->inst_offset = var->inst_offset;
13659                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
13660                                         MonoInst *load, *load2, *load3;
13661                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
13662                                         int reg1, reg2, reg3;
13663                                         MonoInst *info_var = cfg->gsharedvt_info_var;
13664                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
13665
13666                                         /*
13667                                          * gsharedvt local.
13668                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
13669                                          */
13670
13671                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
13672
13673                                         g_assert (info_var);
13674                                         g_assert (locals_var);
13675
13676                                         /* Mark the instruction used to compute the locals var as used */
13677                                         cfg->gsharedvt_locals_var_ins = NULL;
13678
13679                                         /* Load the offset */
13680                                         if (info_var->opcode == OP_REGOFFSET) {
13681                                                 reg1 = alloc_ireg (cfg);
13682                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
13683                                         } else if (info_var->opcode == OP_REGVAR) {
13684                                                 load = NULL;
13685                                                 reg1 = info_var->dreg;
13686                                         } else {
13687                                                 g_assert_not_reached ();
13688                                         }
13689                                         reg2 = alloc_ireg (cfg);
13690                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
13691                                         /* Load the locals area address */
13692                                         reg3 = alloc_ireg (cfg);
13693                                         if (locals_var->opcode == OP_REGOFFSET) {
13694                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
13695                                         } else if (locals_var->opcode == OP_REGVAR) {
13696                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
13697                                         } else {
13698                                                 g_assert_not_reached ();
13699                                         }
13700                                         /* Compute the address */
13701                                         ins->opcode = OP_PADD;
13702                                         ins->sreg1 = reg3;
13703                                         ins->sreg2 = reg2;
13704
13705                                         mono_bblock_insert_before_ins (bb, ins, load3);
13706                                         mono_bblock_insert_before_ins (bb, load3, load2);
13707                                         if (load)
13708                                                 mono_bblock_insert_before_ins (bb, load2, load);
13709                                 } else {
13710                                         g_assert (var->opcode == OP_REGOFFSET);
13711
13712                                         ins->opcode = OP_ADD_IMM;
13713                                         ins->sreg1 = var->inst_basereg;
13714                                         ins->inst_imm = var->inst_offset;
13715                                 }
13716
13717                                 *need_local_opts = TRUE;
13718                                 spec = INS_INFO (ins->opcode);
13719                         }
13720
13721                         if (ins->opcode < MONO_CEE_LAST) {
13722                                 mono_print_ins (ins);
13723                                 g_assert_not_reached ();
13724                         }
13725
13726                         /*
13727                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
13728                          * src register.
13729                          * FIXME:
13730                          */
13731                         if (MONO_IS_STORE_MEMBASE (ins)) {
13732                                 tmp_reg = ins->dreg;
13733                                 ins->dreg = ins->sreg2;
13734                                 ins->sreg2 = tmp_reg;
13735                                 store = TRUE;
13736
13737                                 spec2 [MONO_INST_DEST] = ' ';
13738                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13739                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13740                                 spec2 [MONO_INST_SRC3] = ' ';
13741                                 spec = spec2;
13742                         } else if (MONO_IS_STORE_MEMINDEX (ins))
13743                                 g_assert_not_reached ();
13744                         else
13745                                 store = FALSE;
13746                         no_lvreg = FALSE;
13747
13748                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
13749                                 printf ("\t %.3s %d", spec, ins->dreg);
13750                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
13751                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
13752                                         printf (" %d", sregs [srcindex]);
13753                                 printf ("\n");
13754                         }
13755
13756                         /***************/
13757                         /*    DREG     */
13758                         /***************/
13759                         regtype = spec [MONO_INST_DEST];
13760                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
13761                         prev_dreg = -1;
13762
13763                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
13764                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
13765                                 MonoInst *store_ins;
13766                                 int store_opcode;
13767                                 MonoInst *def_ins = ins;
13768                                 int dreg = ins->dreg; /* The original vreg */
13769
13770                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
13771
13772                                 if (var->opcode == OP_REGVAR) {
13773                                         ins->dreg = var->dreg;
13774                                 } 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)) {
13775                                         /* 
13776                                          * Instead of emitting a load+store, use a _membase opcode.
13777                                          */
13778                                         g_assert (var->opcode == OP_REGOFFSET);
13779                                         if (ins->opcode == OP_MOVE) {
13780                                                 NULLIFY_INS (ins);
13781                                                 def_ins = NULL;
13782                                         } else {
13783                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
13784                                                 ins->inst_basereg = var->inst_basereg;
13785                                                 ins->inst_offset = var->inst_offset;
13786                                                 ins->dreg = -1;
13787                                         }
13788                                         spec = INS_INFO (ins->opcode);
13789                                 } else {
13790                                         guint32 lvreg;
13791
13792                                         g_assert (var->opcode == OP_REGOFFSET);
13793
13794                                         prev_dreg = ins->dreg;
13795
13796                                         /* Invalidate any previous lvreg for this vreg */
13797                                         vreg_to_lvreg [ins->dreg] = 0;
13798
13799                                         lvreg = 0;
13800
13801                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
13802                                                 regtype = 'l';
13803                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
13804                                         }
13805
13806                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
13807
13808 #if SIZEOF_REGISTER != 8
13809                                         if (regtype == 'l') {
13810                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
13811                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13812                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
13813                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
13814                                                 def_ins = store_ins;
13815                                         }
13816                                         else
13817 #endif
13818                                         {
13819                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
13820
13821                                                 /* Try to fuse the store into the instruction itself */
13822                                                 /* FIXME: Add more instructions */
13823                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
13824                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
13825                                                         ins->inst_imm = ins->inst_c0;
13826                                                         ins->inst_destbasereg = var->inst_basereg;
13827                                                         ins->inst_offset = var->inst_offset;
13828                                                         spec = INS_INFO (ins->opcode);
13829                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
13830                                                         ins->opcode = store_opcode;
13831                                                         ins->inst_destbasereg = var->inst_basereg;
13832                                                         ins->inst_offset = var->inst_offset;
13833
13834                                                         no_lvreg = TRUE;
13835
13836                                                         tmp_reg = ins->dreg;
13837                                                         ins->dreg = ins->sreg2;
13838                                                         ins->sreg2 = tmp_reg;
13839                                                         store = TRUE;
13840
13841                                                         spec2 [MONO_INST_DEST] = ' ';
13842                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
13843                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
13844                                                         spec2 [MONO_INST_SRC3] = ' ';
13845                                                         spec = spec2;
13846                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
13847                                                         // FIXME: The backends expect the base reg to be in inst_basereg
13848                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
13849                                                         ins->dreg = -1;
13850                                                         ins->inst_basereg = var->inst_basereg;
13851                                                         ins->inst_offset = var->inst_offset;
13852                                                         spec = INS_INFO (ins->opcode);
13853                                                 } else {
13854                                                         /* printf ("INS: "); mono_print_ins (ins); */
13855                                                         /* Create a store instruction */
13856                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13857
13858                                                         /* Insert it after the instruction */
13859                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13860
13861                                                         def_ins = store_ins;
13862
13863                                                         /* 
13864                                                          * We can't assign ins->dreg to var->dreg here, since the
13865                                                          * sregs could use it. So set a flag, and do it after
13866                                                          * the sregs.
13867                                                          */
13868                                                         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)))
13869                                                                 dest_has_lvreg = TRUE;
13870                                                 }
13871                                         }
13872                                 }
13873
13874                                 if (def_ins && !live_range_start [dreg]) {
13875                                         live_range_start [dreg] = def_ins;
13876                                         live_range_start_bb [dreg] = bb;
13877                                 }
13878
13879                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13880                                         MonoInst *tmp;
13881
13882                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13883                                         tmp->inst_c1 = dreg;
13884                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13885                                 }
13886                         }
13887
13888                         /************/
13889                         /*  SREGS   */
13890                         /************/
13891                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13892                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13893                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13894                                 sreg = sregs [srcindex];
13895
13896                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13897                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13898                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13899                                         MonoInst *use_ins = ins;
13900                                         MonoInst *load_ins;
13901                                         guint32 load_opcode;
13902
13903                                         if (var->opcode == OP_REGVAR) {
13904                                                 sregs [srcindex] = var->dreg;
13905                                                 //mono_inst_set_src_registers (ins, sregs);
13906                                                 live_range_end [sreg] = use_ins;
13907                                                 live_range_end_bb [sreg] = bb;
13908
13909                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13910                                                         MonoInst *tmp;
13911
13912                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13913                                                         /* var->dreg is a hreg */
13914                                                         tmp->inst_c1 = sreg;
13915                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13916                                                 }
13917
13918                                                 continue;
13919                                         }
13920
13921                                         g_assert (var->opcode == OP_REGOFFSET);
13922                                                 
13923                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13924
13925                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13926
13927                                         if (vreg_to_lvreg [sreg]) {
13928                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13929
13930                                                 /* The variable is already loaded to an lvreg */
13931                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13932                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13933                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13934                                                 //mono_inst_set_src_registers (ins, sregs);
13935                                                 continue;
13936                                         }
13937
13938                                         /* Try to fuse the load into the instruction */
13939                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13940                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13941                                                 sregs [0] = var->inst_basereg;
13942                                                 //mono_inst_set_src_registers (ins, sregs);
13943                                                 ins->inst_offset = var->inst_offset;
13944                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13945                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13946                                                 sregs [1] = var->inst_basereg;
13947                                                 //mono_inst_set_src_registers (ins, sregs);
13948                                                 ins->inst_offset = var->inst_offset;
13949                                         } else {
13950                                                 if (MONO_IS_REAL_MOVE (ins)) {
13951                                                         ins->opcode = OP_NOP;
13952                                                         sreg = ins->dreg;
13953                                                 } else {
13954                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13955
13956                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13957
13958                                                         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) {
13959                                                                 if (var->dreg == prev_dreg) {
13960                                                                         /*
13961                                                                          * sreg refers to the value loaded by the load
13962                                                                          * emitted below, but we need to use ins->dreg
13963                                                                          * since it refers to the store emitted earlier.
13964                                                                          */
13965                                                                         sreg = ins->dreg;
13966                                                                 }
13967                                                                 g_assert (sreg != -1);
13968                                                                 vreg_to_lvreg [var->dreg] = sreg;
13969                                                                 g_assert (lvregs_len < 1024);
13970                                                                 lvregs [lvregs_len ++] = var->dreg;
13971                                                         }
13972                                                 }
13973
13974                                                 sregs [srcindex] = sreg;
13975                                                 //mono_inst_set_src_registers (ins, sregs);
13976
13977 #if SIZEOF_REGISTER != 8
13978                                                 if (regtype == 'l') {
13979                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13980                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13981                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13982                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13983                                                         use_ins = load_ins;
13984                                                 }
13985                                                 else
13986 #endif
13987                                                 {
13988 #if SIZEOF_REGISTER == 4
13989                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13990 #endif
13991                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13992                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13993                                                         use_ins = load_ins;
13994                                                 }
13995                                         }
13996
13997                                         if (var->dreg < orig_next_vreg) {
13998                                                 live_range_end [var->dreg] = use_ins;
13999                                                 live_range_end_bb [var->dreg] = bb;
14000                                         }
14001
14002                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14003                                                 MonoInst *tmp;
14004
14005                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14006                                                 tmp->inst_c1 = var->dreg;
14007                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14008                                         }
14009                                 }
14010                         }
14011                         mono_inst_set_src_registers (ins, sregs);
14012
14013                         if (dest_has_lvreg) {
14014                                 g_assert (ins->dreg != -1);
14015                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14016                                 g_assert (lvregs_len < 1024);
14017                                 lvregs [lvregs_len ++] = prev_dreg;
14018                                 dest_has_lvreg = FALSE;
14019                         }
14020
14021                         if (store) {
14022                                 tmp_reg = ins->dreg;
14023                                 ins->dreg = ins->sreg2;
14024                                 ins->sreg2 = tmp_reg;
14025                         }
14026
14027                         if (MONO_IS_CALL (ins)) {
14028                                 /* Clear vreg_to_lvreg array */
14029                                 for (i = 0; i < lvregs_len; i++)
14030                                         vreg_to_lvreg [lvregs [i]] = 0;
14031                                 lvregs_len = 0;
14032                         } else if (ins->opcode == OP_NOP) {
14033                                 ins->dreg = -1;
14034                                 MONO_INST_NULLIFY_SREGS (ins);
14035                         }
14036
14037                         if (cfg->verbose_level > 2)
14038                                 mono_print_ins_index (1, ins);
14039                 }
14040
14041                 /* Extend the live range based on the liveness info */
14042                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14043                         for (i = 0; i < cfg->num_varinfo; i ++) {
14044                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14045
14046                                 if (vreg_is_volatile (cfg, vi->vreg))
14047                                         /* The liveness info is incomplete */
14048                                         continue;
14049
14050                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14051                                         /* Live from at least the first ins of this bb */
14052                                         live_range_start [vi->vreg] = bb->code;
14053                                         live_range_start_bb [vi->vreg] = bb;
14054                                 }
14055
14056                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14057                                         /* Live at least until the last ins of this bb */
14058                                         live_range_end [vi->vreg] = bb->last_ins;
14059                                         live_range_end_bb [vi->vreg] = bb;
14060                                 }
14061                         }
14062                 }
14063         }
14064         
14065 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
14066         /*
14067          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14068          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14069          */
14070         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14071                 for (i = 0; i < cfg->num_varinfo; ++i) {
14072                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14073                         MonoInst *ins;
14074
14075                         if (live_range_start [vreg]) {
14076                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14077                                 ins->inst_c0 = i;
14078                                 ins->inst_c1 = vreg;
14079                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14080                         }
14081                         if (live_range_end [vreg]) {
14082                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14083                                 ins->inst_c0 = i;
14084                                 ins->inst_c1 = vreg;
14085                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14086                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14087                                 else
14088                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14089                         }
14090                 }
14091         }
14092 #endif
14093
14094         if (cfg->gsharedvt_locals_var_ins) {
14095                 /* Nullify if unused */
14096                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14097                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14098         }
14099
14100         g_free (live_range_start);
14101         g_free (live_range_end);
14102         g_free (live_range_start_bb);
14103         g_free (live_range_end_bb);
14104 }
14105
14106 /**
14107  * FIXME:
14108  * - use 'iadd' instead of 'int_add'
14109  * - handling ovf opcodes: decompose in method_to_ir.
14110  * - unify iregs/fregs
14111  *   -> partly done, the missing parts are:
14112  *   - a more complete unification would involve unifying the hregs as well, so
14113  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14114  *     would no longer map to the machine hregs, so the code generators would need to
14115  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14116  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14117  *     fp/non-fp branches speeds it up by about 15%.
14118  * - use sext/zext opcodes instead of shifts
14119  * - add OP_ICALL
14120  * - get rid of TEMPLOADs if possible and use vregs instead
14121  * - clean up usage of OP_P/OP_ opcodes
14122  * - cleanup usage of DUMMY_USE
14123  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14124  *   stack
14125  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14126  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14127  * - make sure handle_stack_args () is called before the branch is emitted
14128  * - when the new IR is done, get rid of all unused stuff
14129  * - COMPARE/BEQ as separate instructions or unify them ?
14130  *   - keeping them separate allows specialized compare instructions like
14131  *     compare_imm, compare_membase
14132  *   - most back ends unify fp compare+branch, fp compare+ceq
14133  * - integrate mono_save_args into inline_method
14134  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14135  * - handle long shift opts on 32 bit platforms somehow: they require 
14136  *   3 sregs (2 for arg1 and 1 for arg2)
14137  * - make byref a 'normal' type.
14138  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14139  *   variable if needed.
14140  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14141  *   like inline_method.
14142  * - remove inlining restrictions
14143  * - fix LNEG and enable cfold of INEG
14144  * - generalize x86 optimizations like ldelema as a peephole optimization
14145  * - add store_mem_imm for amd64
14146  * - optimize the loading of the interruption flag in the managed->native wrappers
14147  * - avoid special handling of OP_NOP in passes
14148  * - move code inserting instructions into one function/macro.
14149  * - try a coalescing phase after liveness analysis
14150  * - add float -> vreg conversion + local optimizations on !x86
14151  * - figure out how to handle decomposed branches during optimizations, ie.
14152  *   compare+branch, op_jump_table+op_br etc.
14153  * - promote RuntimeXHandles to vregs
14154  * - vtype cleanups:
14155  *   - add a NEW_VARLOADA_VREG macro
14156  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14157  *   accessing vtype fields.
14158  * - get rid of I8CONST on 64 bit platforms
14159  * - dealing with the increase in code size due to branches created during opcode
14160  *   decomposition:
14161  *   - use extended basic blocks
14162  *     - all parts of the JIT
14163  *     - handle_global_vregs () && local regalloc
14164  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14165  * - sources of increase in code size:
14166  *   - vtypes
14167  *   - long compares
14168  *   - isinst and castclass
14169  *   - lvregs not allocated to global registers even if used multiple times
14170  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14171  *   meaningful.
14172  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14173  * - add all micro optimizations from the old JIT
14174  * - put tree optimizations into the deadce pass
14175  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14176  *   specific function.
14177  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14178  *   fcompare + branchCC.
14179  * - create a helper function for allocating a stack slot, taking into account 
14180  *   MONO_CFG_HAS_SPILLUP.
14181  * - merge r68207.
14182  * - merge the ia64 switch changes.
14183  * - optimize mono_regstate2_alloc_int/float.
14184  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14185  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14186  *   parts of the tree could be separated by other instructions, killing the tree
14187  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14188  *   instructions if the result of the load is used multiple times ?
14189  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14190  * - LAST MERGE: 108395.
14191  * - when returning vtypes in registers, generate IR and append it to the end of the
14192  *   last bb instead of doing it in the epilog.
14193  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14194  */
14195
14196 /*
14197
14198 NOTES
14199 -----
14200
14201 - When to decompose opcodes:
14202   - earlier: this makes some optimizations hard to implement, since the low level IR
14203   no longer contains the neccessary information. But it is easier to do.
14204   - later: harder to implement, enables more optimizations.
14205 - Branches inside bblocks:
14206   - created when decomposing complex opcodes. 
14207     - branches to another bblock: harmless, but not tracked by the branch 
14208       optimizations, so need to branch to a label at the start of the bblock.
14209     - branches to inside the same bblock: very problematic, trips up the local
14210       reg allocator. Can be fixed by spitting the current bblock, but that is a
14211       complex operation, since some local vregs can become global vregs etc.
14212 - Local/global vregs:
14213   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14214     local register allocator.
14215   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14216     structure, created by mono_create_var (). Assigned to hregs or the stack by
14217     the global register allocator.
14218 - When to do optimizations like alu->alu_imm:
14219   - earlier -> saves work later on since the IR will be smaller/simpler
14220   - later -> can work on more instructions
14221 - Handling of valuetypes:
14222   - When a vtype is pushed on the stack, a new temporary is created, an 
14223     instruction computing its address (LDADDR) is emitted and pushed on
14224     the stack. Need to optimize cases when the vtype is used immediately as in
14225     argument passing, stloc etc.
14226 - Instead of the to_end stuff in the old JIT, simply call the function handling
14227   the values on the stack before emitting the last instruction of the bb.
14228 */
14229
14230 #endif /* DISABLE_JIT */