Merge pull request #2218 from mono/assignProjectConfigurtionFix
[mono.git] / mono / mini / method-to-ir.c
1 /*
2  * method-to-ir.c: Convert CIL to the JIT internal representation
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2002 Ximian, Inc.
9  * Copyright 2003-2010 Novell, Inc (http://www.novell.com)
10  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11  */
12
13 #include <config.h>
14
15 #ifndef DISABLE_JIT
16
17 #include <signal.h>
18
19 #ifdef HAVE_UNISTD_H
20 #include <unistd.h>
21 #endif
22
23 #include <math.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30
31 #ifdef HAVE_ALLOCA_H
32 #include <alloca.h>
33 #endif
34
35 #include <mono/utils/memcheck.h>
36 #include "mini.h"
37 #include <mono/metadata/abi-details.h>
38 #include <mono/metadata/assembly.h>
39 #include <mono/metadata/attrdefs.h>
40 #include <mono/metadata/loader.h>
41 #include <mono/metadata/tabledefs.h>
42 #include <mono/metadata/class.h>
43 #include <mono/metadata/object.h>
44 #include <mono/metadata/exception.h>
45 #include <mono/metadata/opcodes.h>
46 #include <mono/metadata/mono-endian.h>
47 #include <mono/metadata/tokentype.h>
48 #include <mono/metadata/tabledefs.h>
49 #include <mono/metadata/marshal.h>
50 #include <mono/metadata/debug-helpers.h>
51 #include <mono/metadata/mono-debug.h>
52 #include <mono/metadata/mono-debug-debugger.h>
53 #include <mono/metadata/gc-internals.h>
54 #include <mono/metadata/security-manager.h>
55 #include <mono/metadata/threads-types.h>
56 #include <mono/metadata/security-core-clr.h>
57 #include <mono/metadata/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 #include "aot-compiler.h"
73 #include "mini-llvm.h"
74
75 #define BRANCH_COST 10
76 #define INLINE_LENGTH_LIMIT 20
77
78 /* These have 'cfg' as an implicit argument */
79 #define INLINE_FAILURE(msg) do {                                                                        \
80         if ((cfg->method != cfg->current_method) && (cfg->current_method->wrapper_type == MONO_WRAPPER_NONE)) { \
81                 inline_failure (cfg, msg);                                                                              \
82                 goto exception_exit;                                                                                    \
83         } \
84         } while (0)
85 #define CHECK_CFG_EXCEPTION do {\
86                 if (cfg->exception_type != MONO_EXCEPTION_NONE) \
87                         goto exception_exit;                                            \
88         } while (0)
89 #define METHOD_ACCESS_FAILURE(method, cmethod) do {                     \
90                 method_access_failure ((cfg), (method), (cmethod));                     \
91                 goto exception_exit;                                                                            \
92         } while (0)
93 #define FIELD_ACCESS_FAILURE(method, field) do {                                        \
94                 field_access_failure ((cfg), (method), (field));                        \
95                 goto exception_exit;    \
96         } while (0)
97 #define GENERIC_SHARING_FAILURE(opcode) do {            \
98                 if (cfg->gshared) {                                                                     \
99                         gshared_failure (cfg, opcode, __FILE__, __LINE__);      \
100                         goto exception_exit;    \
101                 }                       \
102         } while (0)
103 #define GSHAREDVT_FAILURE(opcode) do {          \
104         if (cfg->gsharedvt) {                                                                                           \
105                 gsharedvt_failure (cfg, opcode, __FILE__, __LINE__);                    \
106                 goto exception_exit;                                                                                    \
107         }                                                                                                                                       \
108         } while (0)
109 #define OUT_OF_MEMORY_FAILURE do {      \
110                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
111                 goto exception_exit;    \
112         } while (0)
113 #define DISABLE_AOT(cfg) do { \
114                 if ((cfg)->verbose_level >= 2)                                            \
115                         printf ("AOT disabled: %s:%d\n", __FILE__, __LINE__);   \
116                 (cfg)->disable_aot = TRUE;                                                        \
117         } while (0)
118 #define LOAD_ERROR do { \
119                 break_on_unverified ();                                                         \
120                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD); \
121                 goto exception_exit;                                                                    \
122         } while (0)
123
124 #define TYPE_LOAD_ERROR(klass) do { \
125                 cfg->exception_ptr = klass; \
126                 LOAD_ERROR;                                     \
127         } while (0)
128
129 #define CHECK_CFG_ERROR do {\
130                 if (!mono_error_ok (&cfg->error)) { \
131                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);        \
132                         goto mono_error_exit; \
133                 } \
134         } while (0)
135
136 /* Determine whenever 'ins' represents a load of the 'this' argument */
137 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
138
139 static int ldind_to_load_membase (int opcode);
140 static int stind_to_store_membase (int opcode);
141
142 int mono_op_to_op_imm (int opcode);
143 int mono_op_to_op_imm_noemul (int opcode);
144
145 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
146
147 static int inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
148                                                   guchar *ip, guint real_offset, gboolean inline_always);
149
150 /* helper methods signatures */
151 static MonoMethodSignature *helper_sig_domain_get;
152 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline;
153
154 /*
155  * Instruction metadata
156  */
157 #ifdef MINI_OP
158 #undef MINI_OP
159 #endif
160 #ifdef MINI_OP3
161 #undef MINI_OP3
162 #endif
163 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
164 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
165 #define NONE ' '
166 #define IREG 'i'
167 #define FREG 'f'
168 #define VREG 'v'
169 #define XREG 'x'
170 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
171 #define LREG IREG
172 #else
173 #define LREG 'l'
174 #endif
175 /* keep in sync with the enum in mini.h */
176 const char
177 ins_info[] = {
178 #include "mini-ops.h"
179 };
180 #undef MINI_OP
181 #undef MINI_OP3
182
183 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
184 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
185 /* 
186  * This should contain the index of the last sreg + 1. This is not the same
187  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
188  */
189 const gint8 ins_sreg_counts[] = {
190 #include "mini-ops.h"
191 };
192 #undef MINI_OP
193 #undef MINI_OP3
194
195 #define MONO_INIT_VARINFO(vi,id) do { \
196         (vi)->range.first_use.pos.bid = 0xffff; \
197         (vi)->reg = -1; \
198         (vi)->idx = (id); \
199 } while (0)
200
201 guint32
202 mono_alloc_ireg (MonoCompile *cfg)
203 {
204         return alloc_ireg (cfg);
205 }
206
207 guint32
208 mono_alloc_lreg (MonoCompile *cfg)
209 {
210         return alloc_lreg (cfg);
211 }
212
213 guint32
214 mono_alloc_freg (MonoCompile *cfg)
215 {
216         return alloc_freg (cfg);
217 }
218
219 guint32
220 mono_alloc_preg (MonoCompile *cfg)
221 {
222         return alloc_preg (cfg);
223 }
224
225 guint32
226 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
227 {
228         return alloc_dreg (cfg, stack_type);
229 }
230
231 /*
232  * mono_alloc_ireg_ref:
233  *
234  *   Allocate an IREG, and mark it as holding a GC ref.
235  */
236 guint32
237 mono_alloc_ireg_ref (MonoCompile *cfg)
238 {
239         return alloc_ireg_ref (cfg);
240 }
241
242 /*
243  * mono_alloc_ireg_mp:
244  *
245  *   Allocate an IREG, and mark it as holding a managed pointer.
246  */
247 guint32
248 mono_alloc_ireg_mp (MonoCompile *cfg)
249 {
250         return alloc_ireg_mp (cfg);
251 }
252
253 /*
254  * mono_alloc_ireg_copy:
255  *
256  *   Allocate an IREG with the same GC type as VREG.
257  */
258 guint32
259 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
260 {
261         if (vreg_is_ref (cfg, vreg))
262                 return alloc_ireg_ref (cfg);
263         else if (vreg_is_mp (cfg, vreg))
264                 return alloc_ireg_mp (cfg);
265         else
266                 return alloc_ireg (cfg);
267 }
268
269 guint
270 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
271 {
272         if (type->byref)
273                 return OP_MOVE;
274
275         type = mini_get_underlying_type (type);
276 handle_enum:
277         switch (type->type) {
278         case MONO_TYPE_I1:
279         case MONO_TYPE_U1:
280                 return OP_MOVE;
281         case MONO_TYPE_I2:
282         case MONO_TYPE_U2:
283                 return OP_MOVE;
284         case MONO_TYPE_I4:
285         case MONO_TYPE_U4:
286                 return OP_MOVE;
287         case MONO_TYPE_I:
288         case MONO_TYPE_U:
289         case MONO_TYPE_PTR:
290         case MONO_TYPE_FNPTR:
291                 return OP_MOVE;
292         case MONO_TYPE_CLASS:
293         case MONO_TYPE_STRING:
294         case MONO_TYPE_OBJECT:
295         case MONO_TYPE_SZARRAY:
296         case MONO_TYPE_ARRAY:    
297                 return OP_MOVE;
298         case MONO_TYPE_I8:
299         case MONO_TYPE_U8:
300 #if SIZEOF_REGISTER == 8
301                 return OP_MOVE;
302 #else
303                 return OP_LMOVE;
304 #endif
305         case MONO_TYPE_R4:
306                 return cfg->r4fp ? OP_RMOVE : OP_FMOVE;
307         case MONO_TYPE_R8:
308                 return OP_FMOVE;
309         case MONO_TYPE_VALUETYPE:
310                 if (type->data.klass->enumtype) {
311                         type = mono_class_enum_basetype (type->data.klass);
312                         goto handle_enum;
313                 }
314                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
315                         return OP_XMOVE;
316                 return OP_VMOVE;
317         case MONO_TYPE_TYPEDBYREF:
318                 return OP_VMOVE;
319         case MONO_TYPE_GENERICINST:
320                 type = &type->data.generic_class->container_class->byval_arg;
321                 goto handle_enum;
322         case MONO_TYPE_VAR:
323         case MONO_TYPE_MVAR:
324                 g_assert (cfg->gshared);
325                 if (mini_type_var_is_vt (type))
326                         return OP_VMOVE;
327                 else
328                         return mono_type_to_regmove (cfg, mini_get_underlying_type (type));
329         default:
330                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
331         }
332         return -1;
333 }
334
335 void
336 mono_print_bb (MonoBasicBlock *bb, const char *msg)
337 {
338         int i;
339         MonoInst *tree;
340
341         printf ("\n%s %d: [IN: ", msg, bb->block_num);
342         for (i = 0; i < bb->in_count; ++i)
343                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
344         printf (", OUT: ");
345         for (i = 0; i < bb->out_count; ++i)
346                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
347         printf (" ]\n");
348         for (tree = bb->code; tree; tree = tree->next)
349                 mono_print_ins_index (-1, tree);
350 }
351
352 void
353 mono_create_helper_signatures (void)
354 {
355         helper_sig_domain_get = mono_create_icall_signature ("ptr");
356         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
357 }
358
359 static MONO_NEVER_INLINE void
360 break_on_unverified (void)
361 {
362         if (mini_get_debug_options ()->break_on_unverified)
363                 G_BREAKPOINT ();
364 }
365
366 static MONO_NEVER_INLINE void
367 method_access_failure (MonoCompile *cfg, MonoMethod *method, MonoMethod *cil_method)
368 {
369         char *method_fname = mono_method_full_name (method, TRUE);
370         char *cil_method_fname = mono_method_full_name (cil_method, TRUE);
371         mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);
372         cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);
373         g_free (method_fname);
374         g_free (cil_method_fname);
375 }
376
377 static MONO_NEVER_INLINE void
378 field_access_failure (MonoCompile *cfg, MonoMethod *method, MonoClassField *field)
379 {
380         char *method_fname = mono_method_full_name (method, TRUE);
381         char *field_fname = mono_field_full_name (field);
382         mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);
383         cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);
384         g_free (method_fname);
385         g_free (field_fname);
386 }
387
388 static MONO_NEVER_INLINE void
389 inline_failure (MonoCompile *cfg, const char *msg)
390 {
391         if (cfg->verbose_level >= 2)
392                 printf ("inline failed: %s\n", msg);
393         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INLINE_FAILED);
394 }
395
396 static MONO_NEVER_INLINE void
397 gshared_failure (MonoCompile *cfg, int opcode, const char *file, int line)
398 {
399         if (cfg->verbose_level > 2)                                                                                     \
400                 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);
401         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
402 }
403
404 static MONO_NEVER_INLINE void
405 gsharedvt_failure (MonoCompile *cfg, int opcode, const char *file, int line)
406 {
407         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);
408         if (cfg->verbose_level >= 2)
409                 printf ("%s\n", cfg->exception_message);
410         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED);
411 }
412
413 /*
414  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
415  * foo<T> (int i) { ldarg.0; box T; }
416  */
417 #define UNVERIFIED do { \
418         if (cfg->gsharedvt) { \
419                 if (cfg->verbose_level > 2)                                                                     \
420                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
421                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
422                 goto exception_exit;                                                                                    \
423         }                                                                                                                                       \
424         break_on_unverified ();                                                                                         \
425         goto unverified;                                                                                                        \
426 } while (0)
427
428 #define GET_BBLOCK(cfg,tblock,ip) do {  \
429                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
430                 if (!(tblock)) {        \
431                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
432             NEW_BBLOCK (cfg, (tblock)); \
433                         (tblock)->cil_code = (ip);      \
434                         ADD_BBLOCK (cfg, (tblock));     \
435                 } \
436         } while (0)
437
438 #if defined(TARGET_X86) || defined(TARGET_AMD64)
439 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
440                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
441                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
442                 (dest)->sreg1 = (sr1); \
443                 (dest)->sreg2 = (sr2); \
444                 (dest)->inst_imm = (imm); \
445                 (dest)->backend.shift_amount = (shift); \
446                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
447         } while (0)
448 #endif
449
450 /* Emit conversions so both operands of a binary opcode are of the same type */
451 static void
452 add_widen_op (MonoCompile *cfg, MonoInst *ins, MonoInst **arg1_ref, MonoInst **arg2_ref)
453 {
454         MonoInst *arg1 = *arg1_ref;
455         MonoInst *arg2 = *arg2_ref;
456
457         if (cfg->r4fp &&
458                 ((arg1->type == STACK_R4 && arg2->type == STACK_R8) ||
459                  (arg1->type == STACK_R8 && arg2->type == STACK_R4))) {
460                 MonoInst *conv;
461
462                 /* Mixing r4/r8 is allowed by the spec */
463                 if (arg1->type == STACK_R4) {
464                         int dreg = alloc_freg (cfg);
465
466                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg1->dreg);
467                         conv->type = STACK_R8;
468                         ins->sreg1 = dreg;
469                         *arg1_ref = conv;
470                 }
471                 if (arg2->type == STACK_R4) {
472                         int dreg = alloc_freg (cfg);
473
474                         EMIT_NEW_UNALU (cfg, conv, OP_RCONV_TO_R8, dreg, arg2->dreg);
475                         conv->type = STACK_R8;
476                         ins->sreg2 = dreg;
477                         *arg2_ref = conv;
478                 }
479         }
480
481 #if SIZEOF_REGISTER == 8
482         /* FIXME: Need to add many more cases */
483         if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {
484                 MonoInst *widen;
485
486                 int dr = alloc_preg (cfg);
487                 EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg);
488                 (ins)->sreg2 = widen->dreg;
489         }
490 #endif
491 }
492
493 #define ADD_BINOP(op) do {      \
494                 MONO_INST_NEW (cfg, ins, (op)); \
495                 sp -= 2;        \
496                 ins->sreg1 = sp [0]->dreg;      \
497                 ins->sreg2 = sp [1]->dreg;      \
498                 type_from_op (cfg, ins, sp [0], sp [1]);        \
499                 CHECK_TYPE (ins);       \
500                 /* Have to insert a widening op */               \
501         add_widen_op (cfg, ins, &sp [0], &sp [1]);               \
502         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
503         MONO_ADD_INS ((cfg)->cbb, (ins)); \
504         *sp++ = mono_decompose_opcode ((cfg), (ins));   \
505         } while (0)
506
507 #define ADD_UNOP(op) do {       \
508                 MONO_INST_NEW (cfg, ins, (op)); \
509                 sp--;   \
510                 ins->sreg1 = sp [0]->dreg;      \
511                 type_from_op (cfg, ins, sp [0], NULL);  \
512                 CHECK_TYPE (ins);       \
513         (ins)->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type); \
514         MONO_ADD_INS ((cfg)->cbb, (ins)); \
515                 *sp++ = mono_decompose_opcode (cfg, ins);       \
516         } while (0)
517
518 #define ADD_BINCOND(next_block) do {    \
519                 MonoInst *cmp;  \
520                 sp -= 2; \
521                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
522                 cmp->sreg1 = sp [0]->dreg;      \
523                 cmp->sreg2 = sp [1]->dreg;      \
524                 type_from_op (cfg, cmp, sp [0], sp [1]);        \
525                 CHECK_TYPE (cmp);       \
526                 add_widen_op (cfg, cmp, &sp [0], &sp [1]);                                              \
527                 type_from_op (cfg, ins, sp [0], sp [1]);                                                        \
528                 ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);   \
529                 GET_BBLOCK (cfg, tblock, target);               \
530                 link_bblock (cfg, cfg->cbb, tblock);    \
531                 ins->inst_true_bb = tblock;     \
532                 if ((next_block)) {     \
533                         link_bblock (cfg, cfg->cbb, (next_block));      \
534                         ins->inst_false_bb = (next_block);      \
535                         start_new_bblock = 1;   \
536                 } else {        \
537                         GET_BBLOCK (cfg, tblock, ip);           \
538                         link_bblock (cfg, cfg->cbb, tblock);    \
539                         ins->inst_false_bb = tblock;    \
540                         start_new_bblock = 2;   \
541                 }       \
542                 if (sp != stack_start) {                                                                        \
543                     handle_stack_args (cfg, stack_start, sp - stack_start); \
544                         CHECK_UNVERIFIABLE (cfg); \
545                 } \
546         MONO_ADD_INS (cfg->cbb, cmp); \
547                 MONO_ADD_INS (cfg->cbb, ins);   \
548         } while (0)
549
550 /* *
551  * link_bblock: Links two basic blocks
552  *
553  * links two basic blocks in the control flow graph, the 'from'
554  * argument is the starting block and the 'to' argument is the block
555  * the control flow ends to after 'from'.
556  */
557 static void
558 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
559 {
560         MonoBasicBlock **newa;
561         int i, found;
562
563 #if 0
564         if (from->cil_code) {
565                 if (to->cil_code)
566                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
567                 else
568                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
569         } else {
570                 if (to->cil_code)
571                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
572                 else
573                         printf ("edge from entry to exit\n");
574         }
575 #endif
576
577         found = FALSE;
578         for (i = 0; i < from->out_count; ++i) {
579                 if (to == from->out_bb [i]) {
580                         found = TRUE;
581                         break;
582                 }
583         }
584         if (!found) {
585                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
586                 for (i = 0; i < from->out_count; ++i) {
587                         newa [i] = from->out_bb [i];
588                 }
589                 newa [i] = to;
590                 from->out_count++;
591                 from->out_bb = newa;
592         }
593
594         found = FALSE;
595         for (i = 0; i < to->in_count; ++i) {
596                 if (from == to->in_bb [i]) {
597                         found = TRUE;
598                         break;
599                 }
600         }
601         if (!found) {
602                 newa = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
603                 for (i = 0; i < to->in_count; ++i) {
604                         newa [i] = to->in_bb [i];
605                 }
606                 newa [i] = from;
607                 to->in_count++;
608                 to->in_bb = newa;
609         }
610 }
611
612 void
613 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
614 {
615         link_bblock (cfg, from, to);
616 }
617
618 /**
619  * mono_find_block_region:
620  *
621  *   We mark each basic block with a region ID. We use that to avoid BB
622  *   optimizations when blocks are in different regions.
623  *
624  * Returns:
625  *   A region token that encodes where this region is, and information
626  *   about the clause owner for this block.
627  *
628  *   The region encodes the try/catch/filter clause that owns this block
629  *   as well as the type.  -1 is a special value that represents a block
630  *   that is in none of try/catch/filter.
631  */
632 static int
633 mono_find_block_region (MonoCompile *cfg, int offset)
634 {
635         MonoMethodHeader *header = cfg->header;
636         MonoExceptionClause *clause;
637         int i;
638
639         for (i = 0; i < header->num_clauses; ++i) {
640                 clause = &header->clauses [i];
641                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
642                     (offset < (clause->handler_offset)))
643                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
644                            
645                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
646                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
647                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
648                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
649                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
650                         else
651                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
652                 }
653         }
654         for (i = 0; i < header->num_clauses; ++i) {
655                 clause = &header->clauses [i];
656
657                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
658                         return ((i + 1) << 8) | clause->flags;
659         }
660
661         return -1;
662 }
663
664 static GList*
665 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
666 {
667         MonoMethodHeader *header = cfg->header;
668         MonoExceptionClause *clause;
669         int i;
670         GList *res = NULL;
671
672         for (i = 0; i < header->num_clauses; ++i) {
673                 clause = &header->clauses [i];
674                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
675                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
676                         if (clause->flags == type)
677                                 res = g_list_append (res, clause);
678                 }
679         }
680         return res;
681 }
682
683 static void
684 mono_create_spvar_for_region (MonoCompile *cfg, int region)
685 {
686         MonoInst *var;
687
688         var = (MonoInst *)g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
689         if (var)
690                 return;
691
692         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
693         /* prevent it from being register allocated */
694         var->flags |= MONO_INST_VOLATILE;
695
696         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
697 }
698
699 MonoInst *
700 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
701 {
702         return (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
703 }
704
705 static MonoInst*
706 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
707 {
708         MonoInst *var;
709
710         var = (MonoInst *)g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
711         if (var)
712                 return var;
713
714         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
715         /* prevent it from being register allocated */
716         var->flags |= MONO_INST_VOLATILE;
717
718         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
719
720         return var;
721 }
722
723 /*
724  * Returns the type used in the eval stack when @type is loaded.
725  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
726  */
727 void
728 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
729 {
730         MonoClass *klass;
731
732         type = mini_get_underlying_type (type);
733         inst->klass = klass = mono_class_from_mono_type (type);
734         if (type->byref) {
735                 inst->type = STACK_MP;
736                 return;
737         }
738
739 handle_enum:
740         switch (type->type) {
741         case MONO_TYPE_VOID:
742                 inst->type = STACK_INV;
743                 return;
744         case MONO_TYPE_I1:
745         case MONO_TYPE_U1:
746         case MONO_TYPE_I2:
747         case MONO_TYPE_U2:
748         case MONO_TYPE_I4:
749         case MONO_TYPE_U4:
750                 inst->type = STACK_I4;
751                 return;
752         case MONO_TYPE_I:
753         case MONO_TYPE_U:
754         case MONO_TYPE_PTR:
755         case MONO_TYPE_FNPTR:
756                 inst->type = STACK_PTR;
757                 return;
758         case MONO_TYPE_CLASS:
759         case MONO_TYPE_STRING:
760         case MONO_TYPE_OBJECT:
761         case MONO_TYPE_SZARRAY:
762         case MONO_TYPE_ARRAY:    
763                 inst->type = STACK_OBJ;
764                 return;
765         case MONO_TYPE_I8:
766         case MONO_TYPE_U8:
767                 inst->type = STACK_I8;
768                 return;
769         case MONO_TYPE_R4:
770                 inst->type = cfg->r4_stack_type;
771                 break;
772         case MONO_TYPE_R8:
773                 inst->type = STACK_R8;
774                 return;
775         case MONO_TYPE_VALUETYPE:
776                 if (type->data.klass->enumtype) {
777                         type = mono_class_enum_basetype (type->data.klass);
778                         goto handle_enum;
779                 } else {
780                         inst->klass = klass;
781                         inst->type = STACK_VTYPE;
782                         return;
783                 }
784         case MONO_TYPE_TYPEDBYREF:
785                 inst->klass = mono_defaults.typed_reference_class;
786                 inst->type = STACK_VTYPE;
787                 return;
788         case MONO_TYPE_GENERICINST:
789                 type = &type->data.generic_class->container_class->byval_arg;
790                 goto handle_enum;
791         case MONO_TYPE_VAR:
792         case MONO_TYPE_MVAR:
793                 g_assert (cfg->gshared);
794                 if (mini_is_gsharedvt_type (type)) {
795                         g_assert (cfg->gsharedvt);
796                         inst->type = STACK_VTYPE;
797                 } else {
798                         type_to_eval_stack_type (cfg, mini_get_underlying_type (type), inst);
799                 }
800                 return;
801         default:
802                 g_error ("unknown type 0x%02x in eval stack type", type->type);
803         }
804 }
805
806 /*
807  * The following tables are used to quickly validate the IL code in type_from_op ().
808  */
809 static const char
810 bin_num_table [STACK_MAX] [STACK_MAX] = {
811         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
812         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
813         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
814         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
815         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV, STACK_R8},
816         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
817         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
818         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
819         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4}
820 };
821
822 static const char 
823 neg_table [] = {
824         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV, STACK_R4
825 };
826
827 /* reduce the size of this table */
828 static const char
829 bin_int_table [STACK_MAX] [STACK_MAX] = {
830         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
831         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
832         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
833         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
834         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
835         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
836         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
837         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
838 };
839
840 static const char
841 bin_comp_table [STACK_MAX] [STACK_MAX] = {
842 /*      Inv i  L  p  F  &  O  vt r4 */
843         {0},
844         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
845         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
846         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
847         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* F, R8 */
848         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
849         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
850         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
851         {0, 0, 0, 0, 1, 0, 0, 0, 1}, /* r, r4 */
852 };
853
854 /* reduce the size of this table */
855 static const char
856 shift_table [STACK_MAX] [STACK_MAX] = {
857         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
858         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
859         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
860         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
861         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
862         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
863         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
864         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
865 };
866
867 /*
868  * Tables to map from the non-specific opcode to the matching
869  * type-specific opcode.
870  */
871 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
872 static const guint16
873 binops_op_map [STACK_MAX] = {
874         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD, 0, 0, OP_RADD-CEE_ADD
875 };
876
877 /* handles from CEE_NEG to CEE_CONV_U8 */
878 static const guint16
879 unops_op_map [STACK_MAX] = {
880         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG, 0, 0, OP_RNEG-CEE_NEG
881 };
882
883 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
884 static const guint16
885 ovfops_op_map [STACK_MAX] = {
886         0, OP_ICONV_TO_U2-CEE_CONV_U2, OP_LCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_FCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, OP_PCONV_TO_U2-CEE_CONV_U2, 0, OP_RCONV_TO_U2-CEE_CONV_U2
887 };
888
889 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
890 static const guint16
891 ovf2ops_op_map [STACK_MAX] = {
892         0, OP_ICONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_LCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_FCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, OP_PCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN, 0, 0, OP_RCONV_TO_OVF_I1_UN-CEE_CONV_OVF_I1_UN
893 };
894
895 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
896 static const guint16
897 ovf3ops_op_map [STACK_MAX] = {
898         0, OP_ICONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_LCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_FCONV_TO_OVF_I1-CEE_CONV_OVF_I1, OP_PCONV_TO_OVF_I1-CEE_CONV_OVF_I1, 0, 0, OP_RCONV_TO_OVF_I1-CEE_CONV_OVF_I1
899 };
900
901 /* handles from CEE_BEQ to CEE_BLT_UN */
902 static const guint16
903 beqops_op_map [STACK_MAX] = {
904         0, OP_IBEQ-CEE_BEQ, OP_LBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_FBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, OP_PBEQ-CEE_BEQ, 0, OP_FBEQ-CEE_BEQ
905 };
906
907 /* handles from CEE_CEQ to CEE_CLT_UN */
908 static const guint16
909 ceqops_op_map [STACK_MAX] = {
910         0, OP_ICEQ-OP_CEQ, OP_LCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_FCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, OP_PCEQ-OP_CEQ, 0, OP_RCEQ-OP_CEQ
911 };
912
913 /*
914  * Sets ins->type (the type on the eval stack) according to the
915  * type of the opcode and the arguments to it.
916  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
917  *
918  * FIXME: this function sets ins->type unconditionally in some cases, but
919  * it should set it to invalid for some types (a conv.x on an object)
920  */
921 static void
922 type_from_op (MonoCompile *cfg, MonoInst *ins, MonoInst *src1, MonoInst *src2)
923 {
924         switch (ins->opcode) {
925         /* binops */
926         case CEE_ADD:
927         case CEE_SUB:
928         case CEE_MUL:
929         case CEE_DIV:
930         case CEE_REM:
931                 /* FIXME: check unverifiable args for STACK_MP */
932                 ins->type = bin_num_table [src1->type] [src2->type];
933                 ins->opcode += binops_op_map [ins->type];
934                 break;
935         case CEE_DIV_UN:
936         case CEE_REM_UN:
937         case CEE_AND:
938         case CEE_OR:
939         case CEE_XOR:
940                 ins->type = bin_int_table [src1->type] [src2->type];
941                 ins->opcode += binops_op_map [ins->type];
942                 break;
943         case CEE_SHL:
944         case CEE_SHR:
945         case CEE_SHR_UN:
946                 ins->type = shift_table [src1->type] [src2->type];
947                 ins->opcode += binops_op_map [ins->type];
948                 break;
949         case OP_COMPARE:
950         case OP_LCOMPARE:
951         case OP_ICOMPARE:
952                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
953                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
954                         ins->opcode = OP_LCOMPARE;
955                 else if (src1->type == STACK_R4)
956                         ins->opcode = OP_RCOMPARE;
957                 else if (src1->type == STACK_R8)
958                         ins->opcode = OP_FCOMPARE;
959                 else
960                         ins->opcode = OP_ICOMPARE;
961                 break;
962         case OP_ICOMPARE_IMM:
963                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
964                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
965                         ins->opcode = OP_LCOMPARE_IMM;          
966                 break;
967         case CEE_BEQ:
968         case CEE_BGE:
969         case CEE_BGT:
970         case CEE_BLE:
971         case CEE_BLT:
972         case CEE_BNE_UN:
973         case CEE_BGE_UN:
974         case CEE_BGT_UN:
975         case CEE_BLE_UN:
976         case CEE_BLT_UN:
977                 ins->opcode += beqops_op_map [src1->type];
978                 break;
979         case OP_CEQ:
980                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
981                 ins->opcode += ceqops_op_map [src1->type];
982                 break;
983         case OP_CGT:
984         case OP_CGT_UN:
985         case OP_CLT:
986         case OP_CLT_UN:
987                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
988                 ins->opcode += ceqops_op_map [src1->type];
989                 break;
990         /* unops */
991         case CEE_NEG:
992                 ins->type = neg_table [src1->type];
993                 ins->opcode += unops_op_map [ins->type];
994                 break;
995         case CEE_NOT:
996                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
997                         ins->type = src1->type;
998                 else
999                         ins->type = STACK_INV;
1000                 ins->opcode += unops_op_map [ins->type];
1001                 break;
1002         case CEE_CONV_I1:
1003         case CEE_CONV_I2:
1004         case CEE_CONV_I4:
1005         case CEE_CONV_U4:
1006                 ins->type = STACK_I4;
1007                 ins->opcode += unops_op_map [src1->type];
1008                 break;
1009         case CEE_CONV_R_UN:
1010                 ins->type = STACK_R8;
1011                 switch (src1->type) {
1012                 case STACK_I4:
1013                 case STACK_PTR:
1014                         ins->opcode = OP_ICONV_TO_R_UN;
1015                         break;
1016                 case STACK_I8:
1017                         ins->opcode = OP_LCONV_TO_R_UN; 
1018                         break;
1019                 }
1020                 break;
1021         case CEE_CONV_OVF_I1:
1022         case CEE_CONV_OVF_U1:
1023         case CEE_CONV_OVF_I2:
1024         case CEE_CONV_OVF_U2:
1025         case CEE_CONV_OVF_I4:
1026         case CEE_CONV_OVF_U4:
1027                 ins->type = STACK_I4;
1028                 ins->opcode += ovf3ops_op_map [src1->type];
1029                 break;
1030         case CEE_CONV_OVF_I_UN:
1031         case CEE_CONV_OVF_U_UN:
1032                 ins->type = STACK_PTR;
1033                 ins->opcode += ovf2ops_op_map [src1->type];
1034                 break;
1035         case CEE_CONV_OVF_I1_UN:
1036         case CEE_CONV_OVF_I2_UN:
1037         case CEE_CONV_OVF_I4_UN:
1038         case CEE_CONV_OVF_U1_UN:
1039         case CEE_CONV_OVF_U2_UN:
1040         case CEE_CONV_OVF_U4_UN:
1041                 ins->type = STACK_I4;
1042                 ins->opcode += ovf2ops_op_map [src1->type];
1043                 break;
1044         case CEE_CONV_U:
1045                 ins->type = STACK_PTR;
1046                 switch (src1->type) {
1047                 case STACK_I4:
1048                         ins->opcode = OP_ICONV_TO_U;
1049                         break;
1050                 case STACK_PTR:
1051                 case STACK_MP:
1052 #if SIZEOF_VOID_P == 8
1053                         ins->opcode = OP_LCONV_TO_U;
1054 #else
1055                         ins->opcode = OP_MOVE;
1056 #endif
1057                         break;
1058                 case STACK_I8:
1059                         ins->opcode = OP_LCONV_TO_U;
1060                         break;
1061                 case STACK_R8:
1062                         ins->opcode = OP_FCONV_TO_U;
1063                         break;
1064                 }
1065                 break;
1066         case CEE_CONV_I8:
1067         case CEE_CONV_U8:
1068                 ins->type = STACK_I8;
1069                 ins->opcode += unops_op_map [src1->type];
1070                 break;
1071         case CEE_CONV_OVF_I8:
1072         case CEE_CONV_OVF_U8:
1073                 ins->type = STACK_I8;
1074                 ins->opcode += ovf3ops_op_map [src1->type];
1075                 break;
1076         case CEE_CONV_OVF_U8_UN:
1077         case CEE_CONV_OVF_I8_UN:
1078                 ins->type = STACK_I8;
1079                 ins->opcode += ovf2ops_op_map [src1->type];
1080                 break;
1081         case CEE_CONV_R4:
1082                 ins->type = cfg->r4_stack_type;
1083                 ins->opcode += unops_op_map [src1->type];
1084                 break;
1085         case CEE_CONV_R8:
1086                 ins->type = STACK_R8;
1087                 ins->opcode += unops_op_map [src1->type];
1088                 break;
1089         case OP_CKFINITE:
1090                 ins->type = STACK_R8;           
1091                 break;
1092         case CEE_CONV_U2:
1093         case CEE_CONV_U1:
1094                 ins->type = STACK_I4;
1095                 ins->opcode += ovfops_op_map [src1->type];
1096                 break;
1097         case CEE_CONV_I:
1098         case CEE_CONV_OVF_I:
1099         case CEE_CONV_OVF_U:
1100                 ins->type = STACK_PTR;
1101                 ins->opcode += ovfops_op_map [src1->type];
1102                 break;
1103         case CEE_ADD_OVF:
1104         case CEE_ADD_OVF_UN:
1105         case CEE_MUL_OVF:
1106         case CEE_MUL_OVF_UN:
1107         case CEE_SUB_OVF:
1108         case CEE_SUB_OVF_UN:
1109                 ins->type = bin_num_table [src1->type] [src2->type];
1110                 ins->opcode += ovfops_op_map [src1->type];
1111                 if (ins->type == STACK_R8)
1112                         ins->type = STACK_INV;
1113                 break;
1114         case OP_LOAD_MEMBASE:
1115                 ins->type = STACK_PTR;
1116                 break;
1117         case OP_LOADI1_MEMBASE:
1118         case OP_LOADU1_MEMBASE:
1119         case OP_LOADI2_MEMBASE:
1120         case OP_LOADU2_MEMBASE:
1121         case OP_LOADI4_MEMBASE:
1122         case OP_LOADU4_MEMBASE:
1123                 ins->type = STACK_PTR;
1124                 break;
1125         case OP_LOADI8_MEMBASE:
1126                 ins->type = STACK_I8;
1127                 break;
1128         case OP_LOADR4_MEMBASE:
1129                 ins->type = cfg->r4_stack_type;
1130                 break;
1131         case OP_LOADR8_MEMBASE:
1132                 ins->type = STACK_R8;
1133                 break;
1134         default:
1135                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1136                 break;
1137         }
1138
1139         if (ins->type == STACK_MP)
1140                 ins->klass = mono_defaults.object_class;
1141 }
1142
1143 static const char 
1144 ldind_type [] = {
1145         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1146 };
1147
1148 #if 0
1149
1150 static const char
1151 param_table [STACK_MAX] [STACK_MAX] = {
1152         {0},
1153 };
1154
1155 static int
1156 check_values_to_signature (MonoInst *args, MonoType *this_ins, MonoMethodSignature *sig)
1157 {
1158         int i;
1159
1160         if (sig->hasthis) {
1161                 switch (args->type) {
1162                 case STACK_I4:
1163                 case STACK_I8:
1164                 case STACK_R8:
1165                 case STACK_VTYPE:
1166                 case STACK_INV:
1167                         return 0;
1168                 }
1169                 args++;
1170         }
1171         for (i = 0; i < sig->param_count; ++i) {
1172                 switch (args [i].type) {
1173                 case STACK_INV:
1174                         return 0;
1175                 case STACK_MP:
1176                         if (!sig->params [i]->byref)
1177                                 return 0;
1178                         continue;
1179                 case STACK_OBJ:
1180                         if (sig->params [i]->byref)
1181                                 return 0;
1182                         switch (sig->params [i]->type) {
1183                         case MONO_TYPE_CLASS:
1184                         case MONO_TYPE_STRING:
1185                         case MONO_TYPE_OBJECT:
1186                         case MONO_TYPE_SZARRAY:
1187                         case MONO_TYPE_ARRAY:
1188                                 break;
1189                         default:
1190                                 return 0;
1191                         }
1192                         continue;
1193                 case STACK_R8:
1194                         if (sig->params [i]->byref)
1195                                 return 0;
1196                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1197                                 return 0;
1198                         continue;
1199                 case STACK_PTR:
1200                 case STACK_I4:
1201                 case STACK_I8:
1202                 case STACK_VTYPE:
1203                         break;
1204                 }
1205                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1206                         return 0;*/
1207         }
1208         return 1;
1209 }
1210 #endif
1211
1212 /*
1213  * When we need a pointer to the current domain many times in a method, we
1214  * call mono_domain_get() once and we store the result in a local variable.
1215  * This function returns the variable that represents the MonoDomain*.
1216  */
1217 inline static MonoInst *
1218 mono_get_domainvar (MonoCompile *cfg)
1219 {
1220         if (!cfg->domainvar)
1221                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1222         return cfg->domainvar;
1223 }
1224
1225 /*
1226  * The got_var contains the address of the Global Offset Table when AOT 
1227  * compiling.
1228  */
1229 MonoInst *
1230 mono_get_got_var (MonoCompile *cfg)
1231 {
1232         if (!cfg->compile_aot || !cfg->backend->need_got_var)
1233                 return NULL;
1234         if (!cfg->got_var) {
1235                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1236         }
1237         return cfg->got_var;
1238 }
1239
1240 static MonoInst *
1241 mono_get_vtable_var (MonoCompile *cfg)
1242 {
1243         g_assert (cfg->gshared);
1244
1245         if (!cfg->rgctx_var) {
1246                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1247                 /* force the var to be stack allocated */
1248                 cfg->rgctx_var->flags |= MONO_INST_VOLATILE;
1249         }
1250
1251         return cfg->rgctx_var;
1252 }
1253
1254 static MonoType*
1255 type_from_stack_type (MonoInst *ins) {
1256         switch (ins->type) {
1257         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1258         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1259         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1260         case STACK_R4: return &mono_defaults.single_class->byval_arg;
1261         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1262         case STACK_MP:
1263                 return &ins->klass->this_arg;
1264         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1265         case STACK_VTYPE: return &ins->klass->byval_arg;
1266         default:
1267                 g_error ("stack type %d to monotype not handled\n", ins->type);
1268         }
1269         return NULL;
1270 }
1271
1272 static G_GNUC_UNUSED int
1273 type_to_stack_type (MonoCompile *cfg, MonoType *t)
1274 {
1275         t = mono_type_get_underlying_type (t);
1276         switch (t->type) {
1277         case MONO_TYPE_I1:
1278         case MONO_TYPE_U1:
1279         case MONO_TYPE_I2:
1280         case MONO_TYPE_U2:
1281         case MONO_TYPE_I4:
1282         case MONO_TYPE_U4:
1283                 return STACK_I4;
1284         case MONO_TYPE_I:
1285         case MONO_TYPE_U:
1286         case MONO_TYPE_PTR:
1287         case MONO_TYPE_FNPTR:
1288                 return STACK_PTR;
1289         case MONO_TYPE_CLASS:
1290         case MONO_TYPE_STRING:
1291         case MONO_TYPE_OBJECT:
1292         case MONO_TYPE_SZARRAY:
1293         case MONO_TYPE_ARRAY:    
1294                 return STACK_OBJ;
1295         case MONO_TYPE_I8:
1296         case MONO_TYPE_U8:
1297                 return STACK_I8;
1298         case MONO_TYPE_R4:
1299                 return cfg->r4_stack_type;
1300         case MONO_TYPE_R8:
1301                 return STACK_R8;
1302         case MONO_TYPE_VALUETYPE:
1303         case MONO_TYPE_TYPEDBYREF:
1304                 return STACK_VTYPE;
1305         case MONO_TYPE_GENERICINST:
1306                 if (mono_type_generic_inst_is_valuetype (t))
1307                         return STACK_VTYPE;
1308                 else
1309                         return STACK_OBJ;
1310                 break;
1311         default:
1312                 g_assert_not_reached ();
1313         }
1314
1315         return -1;
1316 }
1317
1318 static MonoClass*
1319 array_access_to_klass (int opcode)
1320 {
1321         switch (opcode) {
1322         case CEE_LDELEM_U1:
1323                 return mono_defaults.byte_class;
1324         case CEE_LDELEM_U2:
1325                 return mono_defaults.uint16_class;
1326         case CEE_LDELEM_I:
1327         case CEE_STELEM_I:
1328                 return mono_defaults.int_class;
1329         case CEE_LDELEM_I1:
1330         case CEE_STELEM_I1:
1331                 return mono_defaults.sbyte_class;
1332         case CEE_LDELEM_I2:
1333         case CEE_STELEM_I2:
1334                 return mono_defaults.int16_class;
1335         case CEE_LDELEM_I4:
1336         case CEE_STELEM_I4:
1337                 return mono_defaults.int32_class;
1338         case CEE_LDELEM_U4:
1339                 return mono_defaults.uint32_class;
1340         case CEE_LDELEM_I8:
1341         case CEE_STELEM_I8:
1342                 return mono_defaults.int64_class;
1343         case CEE_LDELEM_R4:
1344         case CEE_STELEM_R4:
1345                 return mono_defaults.single_class;
1346         case CEE_LDELEM_R8:
1347         case CEE_STELEM_R8:
1348                 return mono_defaults.double_class;
1349         case CEE_LDELEM_REF:
1350         case CEE_STELEM_REF:
1351                 return mono_defaults.object_class;
1352         default:
1353                 g_assert_not_reached ();
1354         }
1355         return NULL;
1356 }
1357
1358 /*
1359  * We try to share variables when possible
1360  */
1361 static MonoInst *
1362 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1363 {
1364         MonoInst *res;
1365         int pos, vnum;
1366
1367         /* inlining can result in deeper stacks */ 
1368         if (slot >= cfg->header->max_stack)
1369                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1370
1371         pos = ins->type - 1 + slot * STACK_MAX;
1372
1373         switch (ins->type) {
1374         case STACK_I4:
1375         case STACK_I8:
1376         case STACK_R8:
1377         case STACK_PTR:
1378         case STACK_MP:
1379         case STACK_OBJ:
1380                 if ((vnum = cfg->intvars [pos]))
1381                         return cfg->varinfo [vnum];
1382                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1383                 cfg->intvars [pos] = res->inst_c0;
1384                 break;
1385         default:
1386                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1387         }
1388         return res;
1389 }
1390
1391 static void
1392 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1393 {
1394         /* 
1395          * Don't use this if a generic_context is set, since that means AOT can't
1396          * look up the method using just the image+token.
1397          * table == 0 means this is a reference made from a wrapper.
1398          */
1399         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1400                 MonoJumpInfoToken *jump_info_token = (MonoJumpInfoToken *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1401                 jump_info_token->image = image;
1402                 jump_info_token->token = token;
1403                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1404         }
1405 }
1406
1407 /*
1408  * This function is called to handle items that are left on the evaluation stack
1409  * at basic block boundaries. What happens is that we save the values to local variables
1410  * and we reload them later when first entering the target basic block (with the
1411  * handle_loaded_temps () function).
1412  * A single joint point will use the same variables (stored in the array bb->out_stack or
1413  * bb->in_stack, if the basic block is before or after the joint point).
1414  *
1415  * This function needs to be called _before_ emitting the last instruction of
1416  * the bb (i.e. before emitting a branch).
1417  * If the stack merge fails at a join point, cfg->unverifiable is set.
1418  */
1419 static void
1420 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1421 {
1422         int i, bindex;
1423         MonoBasicBlock *bb = cfg->cbb;
1424         MonoBasicBlock *outb;
1425         MonoInst *inst, **locals;
1426         gboolean found;
1427
1428         if (!count)
1429                 return;
1430         if (cfg->verbose_level > 3)
1431                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1432         if (!bb->out_scount) {
1433                 bb->out_scount = count;
1434                 //printf ("bblock %d has out:", bb->block_num);
1435                 found = FALSE;
1436                 for (i = 0; i < bb->out_count; ++i) {
1437                         outb = bb->out_bb [i];
1438                         /* exception handlers are linked, but they should not be considered for stack args */
1439                         if (outb->flags & BB_EXCEPTION_HANDLER)
1440                                 continue;
1441                         //printf (" %d", outb->block_num);
1442                         if (outb->in_stack) {
1443                                 found = TRUE;
1444                                 bb->out_stack = outb->in_stack;
1445                                 break;
1446                         }
1447                 }
1448                 //printf ("\n");
1449                 if (!found) {
1450                         bb->out_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1451                         for (i = 0; i < count; ++i) {
1452                                 /* 
1453                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1454                                  * stack slot and if they are of the same type.
1455                                  * This won't cause conflicts since if 'local' is used to 
1456                                  * store one of the values in the in_stack of a bblock, then
1457                                  * the same variable will be used for the same outgoing stack 
1458                                  * slot as well. 
1459                                  * This doesn't work when inlining methods, since the bblocks
1460                                  * in the inlined methods do not inherit their in_stack from
1461                                  * the bblock they are inlined to. See bug #58863 for an
1462                                  * example.
1463                                  */
1464                                 if (cfg->inlined_method)
1465                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1466                                 else
1467                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1468                         }
1469                 }
1470         }
1471
1472         for (i = 0; i < bb->out_count; ++i) {
1473                 outb = bb->out_bb [i];
1474                 /* exception handlers are linked, but they should not be considered for stack args */
1475                 if (outb->flags & BB_EXCEPTION_HANDLER)
1476                         continue;
1477                 if (outb->in_scount) {
1478                         if (outb->in_scount != bb->out_scount) {
1479                                 cfg->unverifiable = TRUE;
1480                                 return;
1481                         }
1482                         continue; /* check they are the same locals */
1483                 }
1484                 outb->in_scount = count;
1485                 outb->in_stack = bb->out_stack;
1486         }
1487
1488         locals = bb->out_stack;
1489         cfg->cbb = bb;
1490         for (i = 0; i < count; ++i) {
1491                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [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)locals [i]->inst_c0);
1496         }
1497
1498         /*
1499          * It is possible that the out bblocks already have in_stack assigned, and
1500          * the in_stacks differ. In this case, we will store to all the different 
1501          * in_stacks.
1502          */
1503
1504         found = TRUE;
1505         bindex = 0;
1506         while (found) {
1507                 /* Find a bblock which has a different in_stack */
1508                 found = FALSE;
1509                 while (bindex < bb->out_count) {
1510                         outb = bb->out_bb [bindex];
1511                         /* exception handlers are linked, but they should not be considered for stack args */
1512                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1513                                 bindex++;
1514                                 continue;
1515                         }
1516                         if (outb->in_stack != locals) {
1517                                 for (i = 0; i < count; ++i) {
1518                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1519                                         inst->cil_code = sp [i]->cil_code;
1520                                         sp [i] = locals [i];
1521                                         if (cfg->verbose_level > 3)
1522                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1523                                 }
1524                                 locals = outb->in_stack;
1525                                 found = TRUE;
1526                                 break;
1527                         }
1528                         bindex ++;
1529                 }
1530         }
1531 }
1532
1533 static MonoInst*
1534 emit_runtime_constant (MonoCompile *cfg, MonoJumpInfoType patch_type, gpointer data)
1535 {
1536         MonoInst *ins;
1537
1538         if (cfg->compile_aot) {
1539                 EMIT_NEW_AOTCONST (cfg, ins, patch_type, data);
1540         } else {
1541                 MonoJumpInfo ji;
1542                 gpointer target;
1543
1544                 ji.type = patch_type;
1545                 ji.data.target = data;
1546                 target = mono_resolve_patch_target (NULL, cfg->domain, NULL, &ji, FALSE);
1547
1548                 EMIT_NEW_PCONST (cfg, ins, target);
1549         }
1550         return ins;
1551 }
1552
1553 static void
1554 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1555 {
1556         int ibitmap_reg = alloc_preg (cfg);
1557 #ifdef COMPRESSED_INTERFACE_BITMAP
1558         MonoInst *args [2];
1559         MonoInst *res, *ins;
1560         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1561         MONO_ADD_INS (cfg->cbb, ins);
1562         args [0] = ins;
1563         args [1] = emit_runtime_constant (cfg, MONO_PATCH_INFO_IID, klass);
1564         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1565         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1566 #else
1567         int ibitmap_byte_reg = alloc_preg (cfg);
1568
1569         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1570
1571         if (cfg->compile_aot) {
1572                 int iid_reg = alloc_preg (cfg);
1573                 int shifted_iid_reg = alloc_preg (cfg);
1574                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1575                 int masked_iid_reg = alloc_preg (cfg);
1576                 int iid_one_bit_reg = alloc_preg (cfg);
1577                 int iid_bit_reg = alloc_preg (cfg);
1578                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1579                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1580                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1581                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1582                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1583                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1584                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1585                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1586         } else {
1587                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1588                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1589         }
1590 #endif
1591 }
1592
1593 /* 
1594  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1595  * stored in "klass_reg" implements the interface "klass".
1596  */
1597 static void
1598 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1599 {
1600         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1601 }
1602
1603 /* 
1604  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1605  * stored in "vtable_reg" implements the interface "klass".
1606  */
1607 static void
1608 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1609 {
1610         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1611 }
1612
1613 /* 
1614  * Emit code which checks whenever the interface id of @klass is smaller than
1615  * than the value given by max_iid_reg.
1616 */
1617 static void
1618 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1619                                                  MonoBasicBlock *false_target)
1620 {
1621         if (cfg->compile_aot) {
1622                 int iid_reg = alloc_preg (cfg);
1623                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1624                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1625         }
1626         else
1627                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1628         if (false_target)
1629                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1630         else
1631                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1632 }
1633
1634 /* Same as above, but obtains max_iid from a vtable */
1635 static void
1636 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1637                                                                  MonoBasicBlock *false_target)
1638 {
1639         int max_iid_reg = alloc_preg (cfg);
1640                 
1641         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, max_interface_id));
1642         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1643 }
1644
1645 /* Same as above, but obtains max_iid from a klass */
1646 static void
1647 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1648                                                                  MonoBasicBlock *false_target)
1649 {
1650         int max_iid_reg = alloc_preg (cfg);
1651
1652         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, max_interface_id));
1653         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1654 }
1655
1656 static void
1657 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1658 {
1659         int idepth_reg = alloc_preg (cfg);
1660         int stypes_reg = alloc_preg (cfg);
1661         int stype = alloc_preg (cfg);
1662
1663         mono_class_setup_supertypes (klass);
1664
1665         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1666                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1667                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1668                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1669         }
1670         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1671         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1672         if (klass_ins) {
1673                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1674         } else if (cfg->compile_aot) {
1675                 int const_reg = alloc_preg (cfg);
1676                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1677                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1678         } else {
1679                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1680         }
1681         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1682 }
1683
1684 static void
1685 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1686 {
1687         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1688 }
1689
1690 static void
1691 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1692 {
1693         int intf_reg = alloc_preg (cfg);
1694
1695         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1696         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1697         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1698         if (true_target)
1699                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1700         else
1701                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1702 }
1703
1704 /*
1705  * Variant of the above that takes a register to the class, not the vtable.
1706  */
1707 static void
1708 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1709 {
1710         int intf_bit_reg = alloc_preg (cfg);
1711
1712         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1713         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1714         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1715         if (true_target)
1716                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1717         else
1718                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1719 }
1720
1721 static inline void
1722 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1723 {
1724         if (klass_inst) {
1725                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1726         } else {
1727                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
1728                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, ins->dreg);
1729         }
1730         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1731 }
1732
1733 static inline void
1734 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1735 {
1736         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1737 }
1738
1739 static inline void
1740 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1741 {
1742         if (cfg->compile_aot) {
1743                 int const_reg = alloc_preg (cfg);
1744                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1745                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1746         } else {
1747                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1748         }
1749         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1750 }
1751
1752 static void
1753 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1754         
1755 static void
1756 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1757 {
1758         if (klass->rank) {
1759                 int rank_reg = alloc_preg (cfg);
1760                 int eclass_reg = alloc_preg (cfg);
1761
1762                 g_assert (!klass_inst);
1763                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, rank));
1764                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1765                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1766                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
1767                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
1768                 if (klass->cast_class == mono_defaults.object_class) {
1769                         int parent_reg = alloc_preg (cfg);
1770                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
1771                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1772                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1773                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1774                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1775                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1776                 } else if (klass->cast_class == mono_defaults.enum_class) {
1777                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1778                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1779                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1780                 } else {
1781                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1782                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1783                 }
1784
1785                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1786                         /* Check that the object is a vector too */
1787                         int bounds_reg = alloc_preg (cfg);
1788                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
1789                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1790                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1791                 }
1792         } else {
1793                 int idepth_reg = alloc_preg (cfg);
1794                 int stypes_reg = alloc_preg (cfg);
1795                 int stype = alloc_preg (cfg);
1796
1797                 mono_class_setup_supertypes (klass);
1798
1799                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1800                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, idepth));
1801                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1802                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1803                 }
1804                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, supertypes));
1805                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1806                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1807         }
1808 }
1809
1810 static void
1811 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1812 {
1813         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1814 }
1815
1816 static void 
1817 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1818 {
1819         int val_reg;
1820
1821         g_assert (val == 0);
1822
1823         if (align == 0)
1824                 align = 4;
1825
1826         if ((size <= SIZEOF_REGISTER) && (size <= align)) {
1827                 switch (size) {
1828                 case 1:
1829                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1830                         return;
1831                 case 2:
1832                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1833                         return;
1834                 case 4:
1835                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1836                         return;
1837 #if SIZEOF_REGISTER == 8
1838                 case 8:
1839                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1840                         return;
1841 #endif
1842                 }
1843         }
1844
1845         val_reg = alloc_preg (cfg);
1846
1847         if (SIZEOF_REGISTER == 8)
1848                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1849         else
1850                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1851
1852         if (align < 4) {
1853                 /* This could be optimized further if neccesary */
1854                 while (size >= 1) {
1855                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1856                         offset += 1;
1857                         size -= 1;
1858                 }
1859                 return;
1860         }       
1861
1862         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1863                 if (offset % 8) {
1864                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1865                         offset += 4;
1866                         size -= 4;
1867                 }
1868                 while (size >= 8) {
1869                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1870                         offset += 8;
1871                         size -= 8;
1872                 }
1873         }       
1874
1875         while (size >= 4) {
1876                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1877                 offset += 4;
1878                 size -= 4;
1879         }
1880         while (size >= 2) {
1881                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1882                 offset += 2;
1883                 size -= 2;
1884         }
1885         while (size >= 1) {
1886                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1887                 offset += 1;
1888                 size -= 1;
1889         }
1890 }
1891
1892 void 
1893 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1894 {
1895         int cur_reg;
1896
1897         if (align == 0)
1898                 align = 4;
1899
1900         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1901         g_assert (size < 10000);
1902
1903         if (align < 4) {
1904                 /* This could be optimized further if neccesary */
1905                 while (size >= 1) {
1906                         cur_reg = alloc_preg (cfg);
1907                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1908                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1909                         doffset += 1;
1910                         soffset += 1;
1911                         size -= 1;
1912                 }
1913         }
1914
1915         if (!cfg->backend->no_unaligned_access && SIZEOF_REGISTER == 8) {
1916                 while (size >= 8) {
1917                         cur_reg = alloc_preg (cfg);
1918                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1919                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1920                         doffset += 8;
1921                         soffset += 8;
1922                         size -= 8;
1923                 }
1924         }       
1925
1926         while (size >= 4) {
1927                 cur_reg = alloc_preg (cfg);
1928                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1929                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1930                 doffset += 4;
1931                 soffset += 4;
1932                 size -= 4;
1933         }
1934         while (size >= 2) {
1935                 cur_reg = alloc_preg (cfg);
1936                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1937                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1938                 doffset += 2;
1939                 soffset += 2;
1940                 size -= 2;
1941         }
1942         while (size >= 1) {
1943                 cur_reg = alloc_preg (cfg);
1944                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1945                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1946                 doffset += 1;
1947                 soffset += 1;
1948                 size -= 1;
1949         }
1950 }
1951
1952 static void
1953 emit_tls_set (MonoCompile *cfg, int sreg1, MonoTlsKey tls_key)
1954 {
1955         MonoInst *ins, *c;
1956
1957         if (cfg->compile_aot) {
1958                 EMIT_NEW_TLS_OFFSETCONST (cfg, c, tls_key);
1959                 MONO_INST_NEW (cfg, ins, OP_TLS_SET_REG);
1960                 ins->sreg1 = sreg1;
1961                 ins->sreg2 = c->dreg;
1962                 MONO_ADD_INS (cfg->cbb, ins);
1963         } else {
1964                 MONO_INST_NEW (cfg, ins, OP_TLS_SET);
1965                 ins->sreg1 = sreg1;
1966                 ins->inst_offset = mini_get_tls_offset (tls_key);
1967                 MONO_ADD_INS (cfg->cbb, ins);
1968         }
1969 }
1970
1971 /*
1972  * emit_push_lmf:
1973  *
1974  *   Emit IR to push the current LMF onto the LMF stack.
1975  */
1976 static void
1977 emit_push_lmf (MonoCompile *cfg)
1978 {
1979         /*
1980          * Emit IR to push the LMF:
1981          * lmf_addr = <lmf_addr from tls>
1982          * lmf->lmf_addr = lmf_addr
1983          * lmf->prev_lmf = *lmf_addr
1984          * *lmf_addr = lmf
1985          */
1986         int lmf_reg, prev_lmf_reg;
1987         MonoInst *ins, *lmf_ins;
1988
1989         if (!cfg->lmf_ir)
1990                 return;
1991
1992         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
1993                 /* Load current lmf */
1994                 lmf_ins = mono_get_lmf_intrinsic (cfg);
1995                 g_assert (lmf_ins);
1996                 MONO_ADD_INS (cfg->cbb, lmf_ins);
1997                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
1998                 lmf_reg = ins->dreg;
1999                 /* Save previous_lmf */
2000                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), lmf_ins->dreg);
2001                 /* Set new LMF */
2002                 emit_tls_set (cfg, lmf_reg, TLS_KEY_LMF);
2003         } else {
2004                 /*
2005                  * Store lmf_addr in a variable, so it can be allocated to a global register.
2006                  */
2007                 if (!cfg->lmf_addr_var)
2008                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2009
2010 #ifdef HOST_WIN32
2011                 ins = mono_get_jit_tls_intrinsic (cfg);
2012                 if (ins) {
2013                         int jit_tls_dreg = ins->dreg;
2014
2015                         MONO_ADD_INS (cfg->cbb, ins);
2016                         lmf_reg = alloc_preg (cfg);
2017                         EMIT_NEW_BIALU_IMM (cfg, lmf_ins, OP_PADD_IMM, lmf_reg, jit_tls_dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2018                 } else {
2019                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2020                 }
2021 #else
2022                 lmf_ins = mono_get_lmf_addr_intrinsic (cfg);
2023                 if (lmf_ins) {
2024                         MONO_ADD_INS (cfg->cbb, lmf_ins);
2025                 } else {
2026 #ifdef TARGET_IOS
2027                         MonoInst *args [16], *jit_tls_ins, *ins;
2028
2029                         /* Inline mono_get_lmf_addr () */
2030                         /* jit_tls = pthread_getspecific (mono_jit_tls_id); lmf_addr = &jit_tls->lmf; */
2031
2032                         /* Load mono_jit_tls_id */
2033                         if (cfg->compile_aot)
2034                                 EMIT_NEW_AOTCONST (cfg, args [0], MONO_PATCH_INFO_JIT_TLS_ID, NULL);
2035                         else
2036                                 EMIT_NEW_ICONST (cfg, args [0], mono_jit_tls_id);
2037                         /* call pthread_getspecific () */
2038                         jit_tls_ins = mono_emit_jit_icall (cfg, pthread_getspecific, args);
2039                         /* lmf_addr = &jit_tls->lmf */
2040                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, cfg->lmf_addr_var->dreg, jit_tls_ins->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, lmf));
2041                         lmf_ins = ins;
2042 #else
2043                         lmf_ins = mono_emit_jit_icall (cfg, mono_get_lmf_addr, NULL);
2044 #endif
2045                 }
2046 #endif
2047                 lmf_ins->dreg = cfg->lmf_addr_var->dreg;
2048
2049                 EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2050                 lmf_reg = ins->dreg;
2051
2052                 prev_lmf_reg = alloc_preg (cfg);
2053                 /* Save previous_lmf */
2054                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, cfg->lmf_addr_var->dreg, 0);
2055                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), prev_lmf_reg);
2056                 /* Set new lmf */
2057                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, cfg->lmf_addr_var->dreg, 0, lmf_reg);
2058         }
2059 }
2060
2061 /*
2062  * emit_pop_lmf:
2063  *
2064  *   Emit IR to pop the current LMF from the LMF stack.
2065  */
2066 static void
2067 emit_pop_lmf (MonoCompile *cfg)
2068 {
2069         int lmf_reg, lmf_addr_reg, prev_lmf_reg;
2070         MonoInst *ins;
2071
2072         if (!cfg->lmf_ir)
2073                 return;
2074
2075         EMIT_NEW_VARLOADA (cfg, ins, cfg->lmf_var, NULL);
2076         lmf_reg = ins->dreg;
2077
2078         if (cfg->lmf_ir_mono_lmf && mini_tls_get_supported (cfg, TLS_KEY_LMF)) {
2079                 /* Load previous_lmf */
2080                 prev_lmf_reg = alloc_preg (cfg);
2081                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2082                 /* Set new LMF */
2083                 emit_tls_set (cfg, prev_lmf_reg, TLS_KEY_LMF);
2084         } else {
2085                 /*
2086                  * Emit IR to pop the LMF:
2087                  * *(lmf->lmf_addr) = lmf->prev_lmf
2088                  */
2089                 /* This could be called before emit_push_lmf () */
2090                 if (!cfg->lmf_addr_var)
2091                         cfg->lmf_addr_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2092                 lmf_addr_reg = cfg->lmf_addr_var->dreg;
2093
2094                 prev_lmf_reg = alloc_preg (cfg);
2095                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, prev_lmf_reg, lmf_reg, MONO_STRUCT_OFFSET (MonoLMF, previous_lmf));
2096                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, lmf_addr_reg, 0, prev_lmf_reg);
2097         }
2098 }
2099
2100 static void
2101 emit_instrumentation_call (MonoCompile *cfg, void *func)
2102 {
2103         MonoInst *iargs [1];
2104
2105         /*
2106          * Avoid instrumenting inlined methods since it can
2107          * distort profiling results.
2108          */
2109         if (cfg->method != cfg->current_method)
2110                 return;
2111
2112         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) {
2113                 EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
2114                 mono_emit_jit_icall (cfg, func, iargs);
2115         }
2116 }
2117
2118 static int
2119 ret_type_to_call_opcode (MonoCompile *cfg, MonoType *type, int calli, int virt)
2120 {
2121 handle_enum:
2122         type = mini_get_underlying_type (type);
2123         switch (type->type) {
2124         case MONO_TYPE_VOID:
2125                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALL_MEMBASE: OP_VOIDCALL;
2126         case MONO_TYPE_I1:
2127         case MONO_TYPE_U1:
2128         case MONO_TYPE_I2:
2129         case MONO_TYPE_U2:
2130         case MONO_TYPE_I4:
2131         case MONO_TYPE_U4:
2132                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2133         case MONO_TYPE_I:
2134         case MONO_TYPE_U:
2135         case MONO_TYPE_PTR:
2136         case MONO_TYPE_FNPTR:
2137                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2138         case MONO_TYPE_CLASS:
2139         case MONO_TYPE_STRING:
2140         case MONO_TYPE_OBJECT:
2141         case MONO_TYPE_SZARRAY:
2142         case MONO_TYPE_ARRAY:    
2143                 return calli? OP_CALL_REG: virt? OP_CALL_MEMBASE: OP_CALL;
2144         case MONO_TYPE_I8:
2145         case MONO_TYPE_U8:
2146                 return calli? OP_LCALL_REG: virt? OP_LCALL_MEMBASE: OP_LCALL;
2147         case MONO_TYPE_R4:
2148                 if (cfg->r4fp)
2149                         return calli? OP_RCALL_REG: virt? OP_RCALL_MEMBASE: OP_RCALL;
2150                 else
2151                         return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2152         case MONO_TYPE_R8:
2153                 return calli? OP_FCALL_REG: virt? OP_FCALL_MEMBASE: OP_FCALL;
2154         case MONO_TYPE_VALUETYPE:
2155                 if (type->data.klass->enumtype) {
2156                         type = mono_class_enum_basetype (type->data.klass);
2157                         goto handle_enum;
2158                 } else
2159                         return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2160         case MONO_TYPE_TYPEDBYREF:
2161                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2162         case MONO_TYPE_GENERICINST:
2163                 type = &type->data.generic_class->container_class->byval_arg;
2164                 goto handle_enum;
2165         case MONO_TYPE_VAR:
2166         case MONO_TYPE_MVAR:
2167                 /* gsharedvt */
2168                 return calli? OP_VCALL_REG: virt? OP_VCALL_MEMBASE: OP_VCALL;
2169         default:
2170                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
2171         }
2172         return -1;
2173 }
2174
2175 /*
2176  * target_type_is_incompatible:
2177  * @cfg: MonoCompile context
2178  *
2179  * Check that the item @arg on the evaluation stack can be stored
2180  * in the target type (can be a local, or field, etc).
2181  * The cfg arg can be used to check if we need verification or just
2182  * validity checks.
2183  *
2184  * Returns: non-0 value if arg can't be stored on a target.
2185  */
2186 static int
2187 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
2188 {
2189         MonoType *simple_type;
2190         MonoClass *klass;
2191
2192         if (target->byref) {
2193                 /* FIXME: check that the pointed to types match */
2194                 if (arg->type == STACK_MP) {
2195                         MonoClass *base_class = mono_class_from_mono_type (target);
2196                         /* This is needed to handle gshared types + ldaddr */
2197                         simple_type = mini_get_underlying_type (&base_class->byval_arg);
2198                         return target->type != MONO_TYPE_I && arg->klass != base_class && arg->klass != mono_class_from_mono_type (simple_type);
2199                 }
2200                 if (arg->type == STACK_PTR)
2201                         return 0;
2202                 return 1;
2203         }
2204
2205         simple_type = mini_get_underlying_type (target);
2206         switch (simple_type->type) {
2207         case MONO_TYPE_VOID:
2208                 return 1;
2209         case MONO_TYPE_I1:
2210         case MONO_TYPE_U1:
2211         case MONO_TYPE_I2:
2212         case MONO_TYPE_U2:
2213         case MONO_TYPE_I4:
2214         case MONO_TYPE_U4:
2215                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
2216                         return 1;
2217                 return 0;
2218         case MONO_TYPE_PTR:
2219                 /* STACK_MP is needed when setting pinned locals */
2220                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2221                         return 1;
2222                 return 0;
2223         case MONO_TYPE_I:
2224         case MONO_TYPE_U:
2225         case MONO_TYPE_FNPTR:
2226                 /* 
2227                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
2228                  * in native int. (#688008).
2229                  */
2230                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
2231                         return 1;
2232                 return 0;
2233         case MONO_TYPE_CLASS:
2234         case MONO_TYPE_STRING:
2235         case MONO_TYPE_OBJECT:
2236         case MONO_TYPE_SZARRAY:
2237         case MONO_TYPE_ARRAY:    
2238                 if (arg->type != STACK_OBJ)
2239                         return 1;
2240                 /* FIXME: check type compatibility */
2241                 return 0;
2242         case MONO_TYPE_I8:
2243         case MONO_TYPE_U8:
2244                 if (arg->type != STACK_I8)
2245                         return 1;
2246                 return 0;
2247         case MONO_TYPE_R4:
2248                 if (arg->type != cfg->r4_stack_type)
2249                         return 1;
2250                 return 0;
2251         case MONO_TYPE_R8:
2252                 if (arg->type != STACK_R8)
2253                         return 1;
2254                 return 0;
2255         case MONO_TYPE_VALUETYPE:
2256                 if (arg->type != STACK_VTYPE)
2257                         return 1;
2258                 klass = mono_class_from_mono_type (simple_type);
2259                 if (klass != arg->klass)
2260                         return 1;
2261                 return 0;
2262         case MONO_TYPE_TYPEDBYREF:
2263                 if (arg->type != STACK_VTYPE)
2264                         return 1;
2265                 klass = mono_class_from_mono_type (simple_type);
2266                 if (klass != arg->klass)
2267                         return 1;
2268                 return 0;
2269         case MONO_TYPE_GENERICINST:
2270                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2271                         MonoClass *target_class;
2272                         if (arg->type != STACK_VTYPE)
2273                                 return 1;
2274                         klass = mono_class_from_mono_type (simple_type);
2275                         target_class = mono_class_from_mono_type (target);
2276                         /* The second cases is needed when doing partial sharing */
2277                         if (klass != arg->klass && target_class != arg->klass && target_class != mono_class_from_mono_type (mini_get_underlying_type (&arg->klass->byval_arg)))
2278                                 return 1;
2279                         return 0;
2280                 } else {
2281                         if (arg->type != STACK_OBJ)
2282                                 return 1;
2283                         /* FIXME: check type compatibility */
2284                         return 0;
2285                 }
2286         case MONO_TYPE_VAR:
2287         case MONO_TYPE_MVAR:
2288                 g_assert (cfg->gshared);
2289                 if (mini_type_var_is_vt (simple_type)) {
2290                         if (arg->type != STACK_VTYPE)
2291                                 return 1;
2292                 } else {
2293                         if (arg->type != STACK_OBJ)
2294                                 return 1;
2295                 }
2296                 return 0;
2297         default:
2298                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2299         }
2300         return 1;
2301 }
2302
2303 /*
2304  * Prepare arguments for passing to a function call.
2305  * Return a non-zero value if the arguments can't be passed to the given
2306  * signature.
2307  * The type checks are not yet complete and some conversions may need
2308  * casts on 32 or 64 bit architectures.
2309  *
2310  * FIXME: implement this using target_type_is_incompatible ()
2311  */
2312 static int
2313 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2314 {
2315         MonoType *simple_type;
2316         int i;
2317
2318         if (sig->hasthis) {
2319                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2320                         return 1;
2321                 args++;
2322         }
2323         for (i = 0; i < sig->param_count; ++i) {
2324                 if (sig->params [i]->byref) {
2325                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2326                                 return 1;
2327                         continue;
2328                 }
2329                 simple_type = mini_get_underlying_type (sig->params [i]);
2330 handle_enum:
2331                 switch (simple_type->type) {
2332                 case MONO_TYPE_VOID:
2333                         return 1;
2334                         continue;
2335                 case MONO_TYPE_I1:
2336                 case MONO_TYPE_U1:
2337                 case MONO_TYPE_I2:
2338                 case MONO_TYPE_U2:
2339                 case MONO_TYPE_I4:
2340                 case MONO_TYPE_U4:
2341                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2342                                 return 1;
2343                         continue;
2344                 case MONO_TYPE_I:
2345                 case MONO_TYPE_U:
2346                 case MONO_TYPE_PTR:
2347                 case MONO_TYPE_FNPTR:
2348                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2349                                 return 1;
2350                         continue;
2351                 case MONO_TYPE_CLASS:
2352                 case MONO_TYPE_STRING:
2353                 case MONO_TYPE_OBJECT:
2354                 case MONO_TYPE_SZARRAY:
2355                 case MONO_TYPE_ARRAY:    
2356                         if (args [i]->type != STACK_OBJ)
2357                                 return 1;
2358                         continue;
2359                 case MONO_TYPE_I8:
2360                 case MONO_TYPE_U8:
2361                         if (args [i]->type != STACK_I8)
2362                                 return 1;
2363                         continue;
2364                 case MONO_TYPE_R4:
2365                         if (args [i]->type != cfg->r4_stack_type)
2366                                 return 1;
2367                         continue;
2368                 case MONO_TYPE_R8:
2369                         if (args [i]->type != STACK_R8)
2370                                 return 1;
2371                         continue;
2372                 case MONO_TYPE_VALUETYPE:
2373                         if (simple_type->data.klass->enumtype) {
2374                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2375                                 goto handle_enum;
2376                         }
2377                         if (args [i]->type != STACK_VTYPE)
2378                                 return 1;
2379                         continue;
2380                 case MONO_TYPE_TYPEDBYREF:
2381                         if (args [i]->type != STACK_VTYPE)
2382                                 return 1;
2383                         continue;
2384                 case MONO_TYPE_GENERICINST:
2385                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2386                         goto handle_enum;
2387                 case MONO_TYPE_VAR:
2388                 case MONO_TYPE_MVAR:
2389                         /* gsharedvt */
2390                         if (args [i]->type != STACK_VTYPE)
2391                                 return 1;
2392                         continue;
2393                 default:
2394                         g_error ("unknown type 0x%02x in check_call_signature",
2395                                  simple_type->type);
2396                 }
2397         }
2398         return 0;
2399 }
2400
2401 static int
2402 callvirt_to_call (int opcode)
2403 {
2404         switch (opcode) {
2405         case OP_CALL_MEMBASE:
2406                 return OP_CALL;
2407         case OP_VOIDCALL_MEMBASE:
2408                 return OP_VOIDCALL;
2409         case OP_FCALL_MEMBASE:
2410                 return OP_FCALL;
2411         case OP_RCALL_MEMBASE:
2412                 return OP_RCALL;
2413         case OP_VCALL_MEMBASE:
2414                 return OP_VCALL;
2415         case OP_LCALL_MEMBASE:
2416                 return OP_LCALL;
2417         default:
2418                 g_assert_not_reached ();
2419         }
2420
2421         return -1;
2422 }
2423
2424 static int
2425 callvirt_to_call_reg (int opcode)
2426 {
2427         switch (opcode) {
2428         case OP_CALL_MEMBASE:
2429                 return OP_CALL_REG;
2430         case OP_VOIDCALL_MEMBASE:
2431                 return OP_VOIDCALL_REG;
2432         case OP_FCALL_MEMBASE:
2433                 return OP_FCALL_REG;
2434         case OP_RCALL_MEMBASE:
2435                 return OP_RCALL_REG;
2436         case OP_VCALL_MEMBASE:
2437                 return OP_VCALL_REG;
2438         case OP_LCALL_MEMBASE:
2439                 return OP_LCALL_REG;
2440         default:
2441                 g_assert_not_reached ();
2442         }
2443
2444         return -1;
2445 }
2446
2447 /* Either METHOD or IMT_ARG needs to be set */
2448 static void
2449 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2450 {
2451         int method_reg;
2452
2453         if (COMPILE_LLVM (cfg)) {
2454                 if (imt_arg) {
2455                         method_reg = alloc_preg (cfg);
2456                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2457                 } else {
2458                         MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2459                         method_reg = ins->dreg;
2460                 }
2461
2462 #ifdef ENABLE_LLVM
2463                 call->imt_arg_reg = method_reg;
2464 #endif
2465                 mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2466                 return;
2467         }
2468
2469         if (imt_arg) {
2470                 method_reg = alloc_preg (cfg);
2471                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2472         } else {
2473                 MonoInst *ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHODCONST, method);
2474                 method_reg = ins->dreg;
2475         }
2476
2477         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2478 }
2479
2480 static MonoJumpInfo *
2481 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2482 {
2483         MonoJumpInfo *ji = (MonoJumpInfo *)mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2484
2485         ji->ip.i = ip;
2486         ji->type = type;
2487         ji->data.target = target;
2488
2489         return ji;
2490 }
2491
2492 static int
2493 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2494 {
2495         if (cfg->gshared)
2496                 return mono_class_check_context_used (klass);
2497         else
2498                 return 0;
2499 }
2500
2501 static int
2502 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2503 {
2504         if (cfg->gshared)
2505                 return mono_method_check_context_used (method);
2506         else
2507                 return 0;
2508 }
2509
2510 /*
2511  * check_method_sharing:
2512  *
2513  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2514  */
2515 static void
2516 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2517 {
2518         gboolean pass_vtable = FALSE;
2519         gboolean pass_mrgctx = FALSE;
2520
2521         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2522                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2523                 gboolean sharable = FALSE;
2524
2525                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE))
2526                         sharable = TRUE;
2527
2528                 /*
2529                  * Pass vtable iff target method might
2530                  * be shared, which means that sharing
2531                  * is enabled for its class and its
2532                  * context is sharable (and it's not a
2533                  * generic method).
2534                  */
2535                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2536                         pass_vtable = TRUE;
2537         }
2538
2539         if (mini_method_get_context (cmethod) &&
2540                 mini_method_get_context (cmethod)->method_inst) {
2541                 g_assert (!pass_vtable);
2542
2543                 if (mono_method_is_generic_sharable_full (cmethod, TRUE, TRUE, TRUE)) {
2544                         pass_mrgctx = TRUE;
2545                 } else {
2546                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (mono_method_signature (cmethod)))
2547                                 pass_mrgctx = TRUE;
2548                 }
2549         }
2550
2551         if (out_pass_vtable)
2552                 *out_pass_vtable = pass_vtable;
2553         if (out_pass_mrgctx)
2554                 *out_pass_mrgctx = pass_mrgctx;
2555 }
2556
2557 inline static MonoCallInst *
2558 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2559                                          MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
2560 {
2561         MonoType *sig_ret;
2562         MonoCallInst *call;
2563 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2564         int i;
2565 #endif
2566
2567         if (cfg->llvm_only)
2568                 tail = FALSE;
2569
2570         if (tail) {
2571                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
2572
2573                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2574         } else
2575                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (cfg, sig->ret, calli, virtual_));
2576
2577         call->args = args;
2578         call->signature = sig;
2579         call->rgctx_reg = rgctx;
2580         sig_ret = mini_get_underlying_type (sig->ret);
2581
2582         type_to_eval_stack_type ((cfg), sig_ret, &call->inst);
2583
2584         if (tail) {
2585                 if (mini_type_is_vtype (sig_ret)) {
2586                         call->vret_var = cfg->vret_addr;
2587                         //g_assert_not_reached ();
2588                 }
2589         } else if (mini_type_is_vtype (sig_ret)) {
2590                 MonoInst *temp = mono_compile_create_var (cfg, sig_ret, OP_LOCAL);
2591                 MonoInst *loada;
2592
2593                 temp->backend.is_pinvoke = sig->pinvoke;
2594
2595                 /*
2596                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2597                  * address of return value to increase optimization opportunities.
2598                  * Before vtype decomposition, the dreg of the call ins itself represents the
2599                  * fact the call modifies the return value. After decomposition, the call will
2600                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2601                  * will be transformed into an LDADDR.
2602                  */
2603                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2604                 loada->dreg = alloc_preg (cfg);
2605                 loada->inst_p0 = temp;
2606                 /* We reference the call too since call->dreg could change during optimization */
2607                 loada->inst_p1 = call;
2608                 MONO_ADD_INS (cfg->cbb, loada);
2609
2610                 call->inst.dreg = temp->dreg;
2611
2612                 call->vret_var = loada;
2613         } else if (!MONO_TYPE_IS_VOID (sig_ret))
2614                 call->inst.dreg = alloc_dreg (cfg, (MonoStackType)call->inst.type);
2615
2616 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2617         if (COMPILE_SOFT_FLOAT (cfg)) {
2618                 /* 
2619                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2620                  * an icall, but that cannot be done during the call sequence since it would clobber
2621                  * the call registers + the stack. So we do it before emitting the call.
2622                  */
2623                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2624                         MonoType *t;
2625                         MonoInst *in = call->args [i];
2626
2627                         if (i >= sig->hasthis)
2628                                 t = sig->params [i - sig->hasthis];
2629                         else
2630                                 t = &mono_defaults.int_class->byval_arg;
2631                         t = mono_type_get_underlying_type (t);
2632
2633                         if (!t->byref && t->type == MONO_TYPE_R4) {
2634                                 MonoInst *iargs [1];
2635                                 MonoInst *conv;
2636
2637                                 iargs [0] = in;
2638                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2639
2640                                 /* The result will be in an int vreg */
2641                                 call->args [i] = conv;
2642                         }
2643                 }
2644         }
2645 #endif
2646
2647         call->need_unbox_trampoline = unbox_trampoline;
2648
2649 #ifdef ENABLE_LLVM
2650         if (COMPILE_LLVM (cfg))
2651                 mono_llvm_emit_call (cfg, call);
2652         else
2653                 mono_arch_emit_call (cfg, call);
2654 #else
2655         mono_arch_emit_call (cfg, call);
2656 #endif
2657
2658         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2659         cfg->flags |= MONO_CFG_HAS_CALLS;
2660         
2661         return call;
2662 }
2663
2664 static void
2665 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2666 {
2667         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2668         cfg->uses_rgctx_reg = TRUE;
2669         call->rgctx_reg = TRUE;
2670 #ifdef ENABLE_LLVM
2671         call->rgctx_arg_reg = rgctx_reg;
2672 #endif
2673 }       
2674
2675 inline static MonoInst*
2676 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2677 {
2678         MonoCallInst *call;
2679         MonoInst *ins;
2680         int rgctx_reg = -1;
2681         gboolean check_sp = FALSE;
2682
2683         if (cfg->check_pinvoke_callconv && cfg->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
2684                 WrapperInfo *info = mono_marshal_get_wrapper_info (cfg->method);
2685
2686                 if (info && info->subtype == WRAPPER_SUBTYPE_PINVOKE)
2687                         check_sp = TRUE;
2688         }
2689
2690         if (rgctx_arg) {
2691                 rgctx_reg = mono_alloc_preg (cfg);
2692                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2693         }
2694
2695         if (check_sp) {
2696                 if (!cfg->stack_inbalance_var)
2697                         cfg->stack_inbalance_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
2698
2699                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2700                 ins->dreg = cfg->stack_inbalance_var->dreg;
2701                 MONO_ADD_INS (cfg->cbb, ins);
2702         }
2703
2704         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2705
2706         call->inst.sreg1 = addr->dreg;
2707
2708         if (imt_arg)
2709                 emit_imt_argument (cfg, call, NULL, imt_arg);
2710
2711         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2712
2713         if (check_sp) {
2714                 int sp_reg;
2715
2716                 sp_reg = mono_alloc_preg (cfg);
2717
2718                 MONO_INST_NEW (cfg, ins, OP_GET_SP);
2719                 ins->dreg = sp_reg;
2720                 MONO_ADD_INS (cfg->cbb, ins);
2721
2722                 /* Restore the stack so we don't crash when throwing the exception */
2723                 MONO_INST_NEW (cfg, ins, OP_SET_SP);
2724                 ins->sreg1 = cfg->stack_inbalance_var->dreg;
2725                 MONO_ADD_INS (cfg->cbb, ins);
2726
2727                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, cfg->stack_inbalance_var->dreg, sp_reg);
2728                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ExecutionEngineException");
2729         }
2730
2731         if (rgctx_arg)
2732                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2733
2734         return (MonoInst*)call;
2735 }
2736
2737 static MonoInst*
2738 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2739
2740 static MonoInst*
2741 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2742 static MonoInst*
2743 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2744
2745 static MonoInst*
2746 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2747                                                         MonoInst **args, MonoInst *this_ins, MonoInst *imt_arg, MonoInst *rgctx_arg)
2748 {
2749 #ifndef DISABLE_REMOTING
2750         gboolean might_be_remote = FALSE;
2751 #endif
2752         gboolean virtual_ = this_ins != NULL;
2753         gboolean enable_for_aot = TRUE;
2754         int context_used;
2755         MonoCallInst *call;
2756         MonoInst *call_target = NULL;
2757         int rgctx_reg = 0;
2758         gboolean need_unbox_trampoline;
2759
2760         if (!sig)
2761                 sig = mono_method_signature (method);
2762
2763         if (cfg->llvm_only && (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
2764                 MonoInst *icall_args [16];
2765                 MonoInst *ins;
2766
2767                 // FIXME: Optimize this
2768
2769                 guint32 imt_slot = mono_method_get_imt_slot (method);
2770
2771                 icall_args [0] = this_ins;
2772                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
2773                 if (imt_arg) {
2774                         icall_args [2] = imt_arg;
2775                 } else {
2776                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, method);
2777                         icall_args [2] = ins;
2778                 }
2779                 EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
2780
2781                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
2782         }
2783
2784         if (rgctx_arg) {
2785                 rgctx_reg = mono_alloc_preg (cfg);
2786                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2787         }
2788
2789         if (method->string_ctor) {
2790                 /* Create the real signature */
2791                 /* FIXME: Cache these */
2792                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2793                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2794
2795                 sig = ctor_sig;
2796         }
2797
2798         context_used = mini_method_check_context_used (cfg, method);
2799
2800 #ifndef DISABLE_REMOTING
2801         might_be_remote = this_ins && sig->hasthis &&
2802                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2803                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this_ins) || context_used);
2804
2805         if (might_be_remote && context_used) {
2806                 MonoInst *addr;
2807
2808                 g_assert (cfg->gshared);
2809
2810                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2811
2812                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2813         }
2814 #endif
2815
2816         if (cfg->llvm_only && !call_target && virtual_ && (method->flags & METHOD_ATTRIBUTE_VIRTUAL)) {
2817                 // FIXME: Vcall optimizations below
2818                 MonoInst *icall_args [16];
2819                 MonoInst *ins;
2820
2821                 if (sig->generic_param_count) {
2822                         /*
2823                          * Generic virtual call, pass the concrete method as the imt argument.
2824                          */
2825                         imt_arg = emit_get_rgctx_method (cfg, context_used,
2826                                                                                          method, MONO_RGCTX_INFO_METHOD);
2827                 }
2828
2829                 // FIXME: Optimize this
2830
2831                 int slot = mono_method_get_vtable_index (method);
2832
2833                 icall_args [0] = this_ins;
2834                 EMIT_NEW_ICONST (cfg, icall_args [1], slot);
2835                 if (imt_arg) {
2836                         icall_args [2] = imt_arg;
2837                 } else {
2838                         EMIT_NEW_PCONST (cfg, ins, NULL);
2839                         icall_args [2] = ins;
2840                 }
2841                 call_target = mono_emit_jit_icall (cfg, mono_resolve_vcall, icall_args);
2842         }
2843
2844         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2845
2846         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2847
2848 #ifndef DISABLE_REMOTING
2849         if (might_be_remote)
2850                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2851         else
2852 #endif
2853                 call->method = method;
2854         call->inst.flags |= MONO_INST_HAS_METHOD;
2855         call->inst.inst_left = this_ins;
2856         call->tail_call = tail;
2857
2858         if (virtual_) {
2859                 int vtable_reg, slot_reg, this_reg;
2860                 int offset;
2861
2862                 this_reg = this_ins->dreg;
2863
2864                 if (!cfg->llvm_only && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2865                         MonoInst *dummy_use;
2866
2867                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2868
2869                         /* Make a call to delegate->invoke_impl */
2870                         call->inst.inst_basereg = this_reg;
2871                         call->inst.inst_offset = MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2872                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2873
2874                         /* We must emit a dummy use here because the delegate trampoline will
2875                         replace the 'this' argument with the delegate target making this activation
2876                         no longer a root for the delegate.
2877                         This is an issue for delegates that target collectible code such as dynamic
2878                         methods of GC'able assemblies.
2879
2880                         For a test case look into #667921.
2881
2882                         FIXME: a dummy use is not the best way to do it as the local register allocator
2883                         will put it on a caller save register and spil it around the call. 
2884                         Ideally, we would either put it on a callee save register or only do the store part.  
2885                          */
2886                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2887
2888                         return (MonoInst*)call;
2889                 }
2890
2891                 if ((!cfg->compile_aot || enable_for_aot) && 
2892                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2893                          (MONO_METHOD_IS_FINAL (method) &&
2894                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2895                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2896                         /* 
2897                          * the method is not virtual, we just need to ensure this is not null
2898                          * and then we can call the method directly.
2899                          */
2900 #ifndef DISABLE_REMOTING
2901                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2902                                 /* 
2903                                  * The check above ensures method is not gshared, this is needed since
2904                                  * gshared methods can't have wrappers.
2905                                  */
2906                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2907                         }
2908 #endif
2909
2910                         if (!method->string_ctor)
2911                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2912
2913                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2914                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2915                         /*
2916                          * the method is virtual, but we can statically dispatch since either
2917                          * it's class or the method itself are sealed.
2918                          * But first we need to ensure it's not a null reference.
2919                          */
2920                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2921
2922                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2923                 } else if (call_target) {
2924                         vtable_reg = alloc_preg (cfg);
2925                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2926
2927                         call->inst.opcode = callvirt_to_call_reg (call->inst.opcode);
2928                         call->inst.sreg1 = call_target->dreg;
2929                         call->inst.flags &= !MONO_INST_HAS_METHOD;
2930                 } else {
2931                         vtable_reg = alloc_preg (cfg);
2932                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
2933                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2934                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2935                                 emit_imt_argument (cfg, call, call->method, imt_arg);
2936                                 slot_reg = vtable_reg;
2937                                 offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2938                         } else {
2939                                 slot_reg = vtable_reg;
2940                                 offset = MONO_STRUCT_OFFSET (MonoVTable, vtable) +
2941                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2942                                 if (imt_arg) {
2943                                         g_assert (mono_method_signature (method)->generic_param_count);
2944                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2945                                 }
2946                         }
2947
2948                         call->inst.sreg1 = slot_reg;
2949                         call->inst.inst_offset = offset;
2950                         call->is_virtual = TRUE;
2951                 }
2952         }
2953
2954         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2955
2956         if (rgctx_arg)
2957                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2958
2959         return (MonoInst*)call;
2960 }
2961
2962 MonoInst*
2963 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins)
2964 {
2965         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this_ins, NULL, NULL);
2966 }
2967
2968 MonoInst*
2969 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2970                                            MonoInst **args)
2971 {
2972         MonoCallInst *call;
2973
2974         g_assert (sig);
2975
2976         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2977         call->fptr = func;
2978
2979         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2980
2981         return (MonoInst*)call;
2982 }
2983
2984 MonoInst*
2985 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2986 {
2987         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2988
2989         g_assert (info);
2990
2991         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2992 }
2993
2994 /*
2995  * mono_emit_abs_call:
2996  *
2997  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2998  */
2999 inline static MonoInst*
3000 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
3001                                         MonoMethodSignature *sig, MonoInst **args)
3002 {
3003         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
3004         MonoInst *ins;
3005
3006         /* 
3007          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
3008          * handle it.
3009          */
3010         if (cfg->abs_patches == NULL)
3011                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
3012         g_hash_table_insert (cfg->abs_patches, ji, ji);
3013         ins = mono_emit_native_call (cfg, ji, sig, args);
3014         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
3015         return ins;
3016 }
3017
3018 static gboolean
3019 direct_icalls_enabled (MonoCompile *cfg)
3020 {
3021         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
3022 #ifdef TARGET_AMD64
3023         if (cfg->compile_llvm)
3024                 return FALSE;
3025 #endif
3026         if (cfg->gen_sdb_seq_points || cfg->disable_direct_icalls)
3027                 return FALSE;
3028         return TRUE;
3029 }
3030
3031 MonoInst*
3032 mono_emit_jit_icall_by_info (MonoCompile *cfg, MonoJitICallInfo *info, MonoInst **args)
3033 {
3034         /*
3035          * Call the jit icall without a wrapper if possible.
3036          * The wrapper is needed for the following reasons:
3037          * - to handle exceptions thrown using mono_raise_exceptions () from the
3038          *   icall function. The EH code needs the lmf frame pushed by the
3039          *   wrapper to be able to unwind back to managed code.
3040          * - to be able to do stack walks for asynchronously suspended
3041          *   threads when debugging.
3042          */
3043         if (info->no_raise && direct_icalls_enabled (cfg)) {
3044                 char *name;
3045                 int costs;
3046
3047                 if (!info->wrapper_method) {
3048                         name = g_strdup_printf ("__icall_wrapper_%s", info->name);
3049                         info->wrapper_method = mono_marshal_get_icall_wrapper (info->sig, name, info->func, TRUE);
3050                         g_free (name);
3051                         mono_memory_barrier ();
3052                 }
3053
3054                 /*
3055                  * Inline the wrapper method, which is basically a call to the C icall, and
3056                  * an exception check.
3057                  */
3058                 costs = inline_method (cfg, info->wrapper_method, NULL,
3059                                                            args, NULL, cfg->real_offset, TRUE);
3060                 g_assert (costs > 0);
3061                 g_assert (!MONO_TYPE_IS_VOID (info->sig->ret));
3062
3063                 return args [0];
3064         } else {
3065                 return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
3066         }
3067 }
3068  
3069 static MonoInst*
3070 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
3071 {
3072         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
3073                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
3074                         int widen_op = -1;
3075
3076                         /* 
3077                          * Native code might return non register sized integers 
3078                          * without initializing the upper bits.
3079                          */
3080                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
3081                         case OP_LOADI1_MEMBASE:
3082                                 widen_op = OP_ICONV_TO_I1;
3083                                 break;
3084                         case OP_LOADU1_MEMBASE:
3085                                 widen_op = OP_ICONV_TO_U1;
3086                                 break;
3087                         case OP_LOADI2_MEMBASE:
3088                                 widen_op = OP_ICONV_TO_I2;
3089                                 break;
3090                         case OP_LOADU2_MEMBASE:
3091                                 widen_op = OP_ICONV_TO_U2;
3092                                 break;
3093                         default:
3094                                 break;
3095                         }
3096
3097                         if (widen_op != -1) {
3098                                 int dreg = alloc_preg (cfg);
3099                                 MonoInst *widen;
3100
3101                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
3102                                 widen->type = ins->type;
3103                                 ins = widen;
3104                         }
3105                 }
3106         }
3107
3108         return ins;
3109 }
3110
3111 static MonoMethod*
3112 get_memcpy_method (void)
3113 {
3114         static MonoMethod *memcpy_method = NULL;
3115         if (!memcpy_method) {
3116                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
3117                 if (!memcpy_method)
3118                         g_error ("Old corlib found. Install a new one");
3119         }
3120         return memcpy_method;
3121 }
3122
3123 static void
3124 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
3125 {
3126         MonoClassField *field;
3127         gpointer iter = NULL;
3128
3129         while ((field = mono_class_get_fields (klass, &iter))) {
3130                 int foffset;
3131
3132                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
3133                         continue;
3134                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
3135                 if (mini_type_is_reference (mono_field_get_type (field))) {
3136                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
3137                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
3138                 } else {
3139                         MonoClass *field_class = mono_class_from_mono_type (field->type);
3140                         if (field_class->has_references)
3141                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
3142                 }
3143         }
3144 }
3145
3146 static void
3147 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
3148 {
3149         int card_table_shift_bits;
3150         gpointer card_table_mask;
3151         guint8 *card_table;
3152         MonoInst *dummy_use;
3153         int nursery_shift_bits;
3154         size_t nursery_size;
3155
3156         if (!cfg->gen_write_barriers)
3157                 return;
3158
3159         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
3160
3161         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
3162
3163         if (cfg->backend->have_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0 && !COMPILE_LLVM (cfg)) {
3164                 MonoInst *wbarrier;
3165
3166                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
3167                 wbarrier->sreg1 = ptr->dreg;
3168                 wbarrier->sreg2 = value->dreg;
3169                 MONO_ADD_INS (cfg->cbb, wbarrier);
3170         } else if (card_table && !cfg->compile_aot && !mono_gc_card_table_nursery_check ()) {
3171                 int offset_reg = alloc_preg (cfg);
3172                 int card_reg;
3173                 MonoInst *ins;
3174
3175                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
3176                 if (card_table_mask)
3177                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
3178
3179                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
3180                  * IMM's larger than 32bits.
3181                  */
3182                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
3183                 card_reg = ins->dreg;
3184
3185                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
3186                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
3187         } else {
3188                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
3189                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
3190         }
3191
3192         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
3193 }
3194
3195 static gboolean
3196 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
3197 {
3198         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
3199         unsigned need_wb = 0;
3200
3201         if (align == 0)
3202                 align = 4;
3203
3204         /*types with references can't have alignment smaller than sizeof(void*) */
3205         if (align < SIZEOF_VOID_P)
3206                 return FALSE;
3207
3208         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
3209         if (size > 32 * SIZEOF_VOID_P)
3210                 return FALSE;
3211
3212         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
3213
3214         /* We don't unroll more than 5 stores to avoid code bloat. */
3215         if (size > 5 * SIZEOF_VOID_P) {
3216                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
3217                 size += (SIZEOF_VOID_P - 1);
3218                 size &= ~(SIZEOF_VOID_P - 1);
3219
3220                 EMIT_NEW_ICONST (cfg, iargs [2], size);
3221                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
3222                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
3223                 return TRUE;
3224         }
3225
3226         destreg = iargs [0]->dreg;
3227         srcreg = iargs [1]->dreg;
3228         offset = 0;
3229
3230         dest_ptr_reg = alloc_preg (cfg);
3231         tmp_reg = alloc_preg (cfg);
3232
3233         /*tmp = dreg*/
3234         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
3235
3236         while (size >= SIZEOF_VOID_P) {
3237                 MonoInst *load_inst;
3238                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
3239                 load_inst->dreg = tmp_reg;
3240                 load_inst->inst_basereg = srcreg;
3241                 load_inst->inst_offset = offset;
3242                 MONO_ADD_INS (cfg->cbb, load_inst);
3243
3244                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
3245
3246                 if (need_wb & 0x1)
3247                         emit_write_barrier (cfg, iargs [0], load_inst);
3248
3249                 offset += SIZEOF_VOID_P;
3250                 size -= SIZEOF_VOID_P;
3251                 need_wb >>= 1;
3252
3253                 /*tmp += sizeof (void*)*/
3254                 if (size >= SIZEOF_VOID_P) {
3255                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
3256                         MONO_ADD_INS (cfg->cbb, iargs [0]);
3257                 }
3258         }
3259
3260         /* Those cannot be references since size < sizeof (void*) */
3261         while (size >= 4) {
3262                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
3263                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
3264                 offset += 4;
3265                 size -= 4;
3266         }
3267
3268         while (size >= 2) {
3269                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
3270                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
3271                 offset += 2;
3272                 size -= 2;
3273         }
3274
3275         while (size >= 1) {
3276                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
3277                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
3278                 offset += 1;
3279                 size -= 1;
3280         }
3281
3282         return TRUE;
3283 }
3284
3285 /*
3286  * Emit code to copy a valuetype of type @klass whose address is stored in
3287  * @src->dreg to memory whose address is stored at @dest->dreg.
3288  */
3289 void
3290 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
3291 {
3292         MonoInst *iargs [4];
3293         int n;
3294         guint32 align = 0;
3295         MonoMethod *memcpy_method;
3296         MonoInst *size_ins = NULL;
3297         MonoInst *memcpy_ins = NULL;
3298
3299         g_assert (klass);
3300         if (cfg->gshared)
3301                 klass = mono_class_from_mono_type (mini_get_underlying_type (&klass->byval_arg));
3302
3303         /*
3304          * This check breaks with spilled vars... need to handle it during verification anyway.
3305          * g_assert (klass && klass == src->klass && klass == dest->klass);
3306          */
3307
3308         if (mini_is_gsharedvt_klass (klass)) {
3309                 g_assert (!native);
3310                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3311                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
3312         }
3313
3314         if (native)
3315                 n = mono_class_native_size (klass, &align);
3316         else
3317                 n = mono_class_value_size (klass, &align);
3318
3319         /* if native is true there should be no references in the struct */
3320         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
3321                 /* Avoid barriers when storing to the stack */
3322                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
3323                           (dest->opcode == OP_LDADDR))) {
3324                         int context_used;
3325
3326                         iargs [0] = dest;
3327                         iargs [1] = src;
3328
3329                         context_used = mini_class_check_context_used (cfg, klass);
3330
3331                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
3332                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
3333                                 return;
3334                         } else if (context_used) {
3335                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3336                         }  else {
3337                                 iargs [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, klass);
3338                                 if (!cfg->compile_aot)
3339                                         mono_class_compute_gc_descriptor (klass);
3340                         }
3341
3342                         if (size_ins)
3343                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3344                         else
3345                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3346                         return;
3347                 }
3348         }
3349
3350         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 8) {
3351                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3352                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3353         } else {
3354                 iargs [0] = dest;
3355                 iargs [1] = src;
3356                 if (size_ins)
3357                         iargs [2] = size_ins;
3358                 else
3359                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3360                 
3361                 memcpy_method = get_memcpy_method ();
3362                 if (memcpy_ins)
3363                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3364                 else
3365                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3366         }
3367 }
3368
3369 static MonoMethod*
3370 get_memset_method (void)
3371 {
3372         static MonoMethod *memset_method = NULL;
3373         if (!memset_method) {
3374                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3375                 if (!memset_method)
3376                         g_error ("Old corlib found. Install a new one");
3377         }
3378         return memset_method;
3379 }
3380
3381 void
3382 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3383 {
3384         MonoInst *iargs [3];
3385         int n;
3386         guint32 align;
3387         MonoMethod *memset_method;
3388         MonoInst *size_ins = NULL;
3389         MonoInst *bzero_ins = NULL;
3390         static MonoMethod *bzero_method;
3391
3392         /* FIXME: Optimize this for the case when dest is an LDADDR */
3393         mono_class_init (klass);
3394         if (mini_is_gsharedvt_klass (klass)) {
3395                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3396                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3397                 if (!bzero_method)
3398                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3399                 g_assert (bzero_method);
3400                 iargs [0] = dest;
3401                 iargs [1] = size_ins;
3402                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3403                 return;
3404         }
3405
3406         n = mono_class_value_size (klass, &align);
3407
3408         if (n <= sizeof (gpointer) * 8) {
3409                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3410         }
3411         else {
3412                 memset_method = get_memset_method ();
3413                 iargs [0] = dest;
3414                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3415                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3416                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3417         }
3418 }
3419
3420 /*
3421  * emit_get_rgctx:
3422  *
3423  *   Emit IR to return either the this pointer for instance method,
3424  * or the mrgctx for static methods.
3425  */
3426 static MonoInst*
3427 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3428 {
3429         MonoInst *this_ins = NULL;
3430
3431         g_assert (cfg->gshared);
3432
3433         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3434                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3435                         !method->klass->valuetype)
3436                 EMIT_NEW_ARGLOAD (cfg, this_ins, 0);
3437
3438         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3439                 MonoInst *mrgctx_loc, *mrgctx_var;
3440
3441                 g_assert (!this_ins);
3442                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3443
3444                 mrgctx_loc = mono_get_vtable_var (cfg);
3445                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3446
3447                 return mrgctx_var;
3448         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3449                 MonoInst *vtable_loc, *vtable_var;
3450
3451                 g_assert (!this_ins);
3452
3453                 vtable_loc = mono_get_vtable_var (cfg);
3454                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3455
3456                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3457                         MonoInst *mrgctx_var = vtable_var;
3458                         int vtable_reg;
3459
3460                         vtable_reg = alloc_preg (cfg);
3461                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, MONO_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3462                         vtable_var->type = STACK_PTR;
3463                 }
3464
3465                 return vtable_var;
3466         } else {
3467                 MonoInst *ins;
3468                 int vtable_reg;
3469         
3470                 vtable_reg = alloc_preg (cfg);
3471                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this_ins->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3472                 return ins;
3473         }
3474 }
3475
3476 static MonoJumpInfoRgctxEntry *
3477 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3478 {
3479         MonoJumpInfoRgctxEntry *res = (MonoJumpInfoRgctxEntry *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3480         res->method = method;
3481         res->in_mrgctx = in_mrgctx;
3482         res->data = (MonoJumpInfo *)mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3483         res->data->type = patch_type;
3484         res->data->data.target = patch_data;
3485         res->info_type = info_type;
3486
3487         return res;
3488 }
3489
3490 static inline MonoInst*
3491 emit_rgctx_fetch_inline (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3492 {
3493         MonoInst *args [16];
3494         MonoInst *call;
3495
3496         // FIXME: No fastpath since the slot is not a compile time constant
3497         args [0] = rgctx;
3498         EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_RGCTX_SLOT_INDEX, entry);
3499         if (entry->in_mrgctx)
3500                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3501         else
3502                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3503         return call;
3504 #if 0
3505         /*
3506          * FIXME: This can be called during decompose, which is a problem since it creates
3507          * new bblocks.
3508          * Also, the fastpath doesn't work since the slot number is dynamically allocated.
3509          */
3510         int i, slot, depth, index, rgctx_reg, val_reg, res_reg;
3511         gboolean mrgctx;
3512         MonoBasicBlock *is_null_bb, *end_bb;
3513         MonoInst *res, *ins, *call;
3514         MonoInst *args[16];
3515
3516         slot = mini_get_rgctx_entry_slot (entry);
3517
3518         mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
3519         index = MONO_RGCTX_SLOT_INDEX (slot);
3520         if (mrgctx)
3521                 index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
3522         for (depth = 0; ; ++depth) {
3523                 int size = mono_class_rgctx_get_array_size (depth, mrgctx);
3524
3525                 if (index < size - 1)
3526                         break;
3527                 index -= size - 1;
3528         }
3529
3530         NEW_BBLOCK (cfg, end_bb);
3531         NEW_BBLOCK (cfg, is_null_bb);
3532
3533         if (mrgctx) {
3534                 rgctx_reg = rgctx->dreg;
3535         } else {
3536                 rgctx_reg = alloc_preg (cfg);
3537
3538                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, rgctx_reg, rgctx->dreg, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context));
3539                 // FIXME: Avoid this check by allocating the table when the vtable is created etc.
3540                 NEW_BBLOCK (cfg, is_null_bb);
3541
3542                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3543                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3544         }
3545
3546         for (i = 0; i < depth; ++i) {
3547                 int array_reg = alloc_preg (cfg);
3548
3549                 /* load ptr to next array */
3550                 if (mrgctx && i == 0)
3551                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT);
3552                 else
3553                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, rgctx_reg, 0);
3554                 rgctx_reg = array_reg;
3555                 /* is the ptr null? */
3556                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
3557                 /* if yes, jump to actual trampoline */
3558                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3559         }
3560
3561         /* fetch slot */
3562         val_reg = alloc_preg (cfg);
3563         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, val_reg, rgctx_reg, (index + 1) * sizeof (gpointer));
3564         /* is the slot null? */
3565         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, val_reg, 0);
3566         /* if yes, jump to actual trampoline */
3567         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3568
3569         /* Fastpath */
3570         res_reg = alloc_preg (cfg);
3571         MONO_INST_NEW (cfg, ins, OP_MOVE);
3572         ins->dreg = res_reg;
3573         ins->sreg1 = val_reg;
3574         MONO_ADD_INS (cfg->cbb, ins);
3575         res = ins;
3576         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3577
3578         /* Slowpath */
3579         MONO_START_BB (cfg, is_null_bb);
3580         args [0] = rgctx;
3581         EMIT_NEW_ICONST (cfg, args [1], index);
3582         if (mrgctx)
3583                 call = mono_emit_jit_icall (cfg, mono_fill_method_rgctx, args);
3584         else
3585                 call = mono_emit_jit_icall (cfg, mono_fill_class_rgctx, args);
3586         MONO_INST_NEW (cfg, ins, OP_MOVE);
3587         ins->dreg = res_reg;
3588         ins->sreg1 = call->dreg;
3589         MONO_ADD_INS (cfg->cbb, ins);
3590         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3591
3592         MONO_START_BB (cfg, end_bb);
3593
3594         return res;
3595 #endif
3596 }
3597
3598 /*
3599  * emit_rgctx_fetch:
3600  *
3601  *   Emit IR to load the value of the rgctx entry ENTRY from the rgctx
3602  * given by RGCTX.
3603  */
3604 static inline MonoInst*
3605 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3606 {
3607         if (cfg->llvm_only)
3608                 return emit_rgctx_fetch_inline (cfg, rgctx, entry);
3609         else
3610                 return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3611 }
3612
3613 static MonoInst*
3614 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3615                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3616 {
3617         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);
3618         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3619
3620         return emit_rgctx_fetch (cfg, rgctx, entry);
3621 }
3622
3623 static MonoInst*
3624 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3625                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3626 {
3627         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);
3628         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3629
3630         return emit_rgctx_fetch (cfg, rgctx, entry);
3631 }
3632
3633 static MonoInst*
3634 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3635                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3636 {
3637         MonoJumpInfoGSharedVtCall *call_info;
3638         MonoJumpInfoRgctxEntry *entry;
3639         MonoInst *rgctx;
3640
3641         call_info = (MonoJumpInfoGSharedVtCall *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3642         call_info->sig = sig;
3643         call_info->method = cmethod;
3644
3645         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);
3646         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3647
3648         return emit_rgctx_fetch (cfg, rgctx, entry);
3649 }
3650
3651 /*
3652  * emit_get_rgctx_virt_method:
3653  *
3654  *   Return data for method VIRT_METHOD for a receiver of type KLASS.
3655  */
3656 static MonoInst*
3657 emit_get_rgctx_virt_method (MonoCompile *cfg, int context_used,
3658                                                         MonoClass *klass, MonoMethod *virt_method, MonoRgctxInfoType rgctx_type)
3659 {
3660         MonoJumpInfoVirtMethod *info;
3661         MonoJumpInfoRgctxEntry *entry;
3662         MonoInst *rgctx;
3663
3664         info = (MonoJumpInfoVirtMethod *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoVirtMethod));
3665         info->klass = klass;
3666         info->method = virt_method;
3667
3668         entry = mono_patch_info_rgctx_entry_new (cfg->mempool, cfg->current_method, context_used & MONO_GENERIC_CONTEXT_USED_METHOD, MONO_PATCH_INFO_VIRT_METHOD, info, rgctx_type);
3669         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3670
3671         return emit_rgctx_fetch (cfg, rgctx, entry);
3672 }
3673
3674 static MonoInst*
3675 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3676                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3677 {
3678         MonoJumpInfoRgctxEntry *entry;
3679         MonoInst *rgctx;
3680
3681         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);
3682         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3683
3684         return emit_rgctx_fetch (cfg, rgctx, entry);
3685 }
3686
3687 /*
3688  * emit_get_rgctx_method:
3689  *
3690  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3691  * normal constants, else emit a load from the rgctx.
3692  */
3693 static MonoInst*
3694 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3695                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3696 {
3697         if (!context_used) {
3698                 MonoInst *ins;
3699
3700                 switch (rgctx_type) {
3701                 case MONO_RGCTX_INFO_METHOD:
3702                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3703                         return ins;
3704                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3705                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3706                         return ins;
3707                 default:
3708                         g_assert_not_reached ();
3709                 }
3710         } else {
3711                 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);
3712                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3713
3714                 return emit_rgctx_fetch (cfg, rgctx, entry);
3715         }
3716 }
3717
3718 static MonoInst*
3719 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3720                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3721 {
3722         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);
3723         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3724
3725         return emit_rgctx_fetch (cfg, rgctx, entry);
3726 }
3727
3728 static int
3729 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3730 {
3731         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3732         MonoRuntimeGenericContextInfoTemplate *template_;
3733         int i, idx;
3734
3735         g_assert (info);
3736
3737         for (i = 0; i < info->num_entries; ++i) {
3738                 MonoRuntimeGenericContextInfoTemplate *otemplate = &info->entries [i];
3739
3740                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3741                         return i;
3742         }
3743
3744         if (info->num_entries == info->count_entries) {
3745                 MonoRuntimeGenericContextInfoTemplate *new_entries;
3746                 int new_count_entries = info->count_entries ? info->count_entries * 2 : 16;
3747
3748                 new_entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * new_count_entries);
3749
3750                 memcpy (new_entries, info->entries, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
3751                 info->entries = new_entries;
3752                 info->count_entries = new_count_entries;
3753         }
3754
3755         idx = info->num_entries;
3756         template_ = &info->entries [idx];
3757         template_->info_type = rgctx_type;
3758         template_->data = data;
3759
3760         info->num_entries ++;
3761
3762         return idx;
3763 }
3764
3765 /*
3766  * emit_get_gsharedvt_info:
3767  *
3768  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3769  */
3770 static MonoInst*
3771 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3772 {
3773         MonoInst *ins;
3774         int idx, dreg;
3775
3776         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3777         /* Load info->entries [idx] */
3778         dreg = alloc_preg (cfg);
3779         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3780
3781         return ins;
3782 }
3783
3784 static MonoInst*
3785 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3786 {
3787         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3788 }
3789
3790 /*
3791  * On return the caller must check @klass for load errors.
3792  */
3793 static void
3794 emit_class_init (MonoCompile *cfg, MonoClass *klass)
3795 {
3796         MonoInst *vtable_arg;
3797         int context_used;
3798
3799         context_used = mini_class_check_context_used (cfg, klass);
3800
3801         if (context_used) {
3802                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3803                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3804         } else {
3805                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3806
3807                 if (!vtable)
3808                         return;
3809                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3810         }
3811
3812         if (!COMPILE_LLVM (cfg) && cfg->backend->have_op_generic_class_init) {
3813                 MonoInst *ins;
3814
3815                 /*
3816                  * Using an opcode instead of emitting IR here allows the hiding of the call inside the opcode,
3817                  * so this doesn't have to clobber any regs and it doesn't break basic blocks.
3818                  */
3819                 MONO_INST_NEW (cfg, ins, OP_GENERIC_CLASS_INIT);
3820                 ins->sreg1 = vtable_arg->dreg;
3821                 MONO_ADD_INS (cfg->cbb, ins);
3822         } else {
3823                 static int byte_offset = -1;
3824                 static guint8 bitmask;
3825                 int bits_reg, inited_reg;
3826                 MonoBasicBlock *inited_bb;
3827                 MonoInst *args [16];
3828
3829                 if (byte_offset < 0)
3830                         mono_marshal_find_bitfield_offset (MonoVTable, initialized, &byte_offset, &bitmask);
3831
3832                 bits_reg = alloc_ireg (cfg);
3833                 inited_reg = alloc_ireg (cfg);
3834
3835                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, bits_reg, vtable_arg->dreg, byte_offset);
3836                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, inited_reg, bits_reg, bitmask);
3837
3838                 NEW_BBLOCK (cfg, inited_bb);
3839
3840                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, inited_reg, 0);
3841                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, inited_bb);
3842
3843                 args [0] = vtable_arg;
3844                 mono_emit_jit_icall (cfg, mono_generic_class_init, args);
3845
3846                 MONO_START_BB (cfg, inited_bb);
3847         }
3848 }
3849
3850 static void
3851 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3852 {
3853         MonoInst *ins;
3854
3855         if (cfg->gen_seq_points && cfg->method == method) {
3856                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3857                 if (nonempty_stack)
3858                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3859                 MONO_ADD_INS (cfg->cbb, ins);
3860         }
3861 }
3862
3863 static void
3864 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check)
3865 {
3866         if (mini_get_debug_options ()->better_cast_details) {
3867                 int vtable_reg = alloc_preg (cfg);
3868                 int klass_reg = alloc_preg (cfg);
3869                 MonoBasicBlock *is_null_bb = NULL;
3870                 MonoInst *tls_get;
3871                 int to_klass_reg, context_used;
3872
3873                 if (null_check) {
3874                         NEW_BBLOCK (cfg, is_null_bb);
3875
3876                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3877                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3878                 }
3879
3880                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3881                 if (!tls_get) {
3882                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3883                         exit (1);
3884                 }
3885
3886                 MONO_ADD_INS (cfg->cbb, tls_get);
3887                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3888                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3889
3890                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3891
3892                 context_used = mini_class_check_context_used (cfg, klass);
3893                 if (context_used) {
3894                         MonoInst *class_ins;
3895
3896                         class_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3897                         to_klass_reg = class_ins->dreg;
3898                 } else {
3899                         to_klass_reg = alloc_preg (cfg);
3900                         MONO_EMIT_NEW_CLASSCONST (cfg, to_klass_reg, klass);
3901                 }
3902                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3903
3904                 if (null_check)
3905                         MONO_START_BB (cfg, is_null_bb);
3906         }
3907 }
3908
3909 static void
3910 reset_cast_details (MonoCompile *cfg)
3911 {
3912         /* Reset the variables holding the cast details */
3913         if (mini_get_debug_options ()->better_cast_details) {
3914                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3915
3916                 MONO_ADD_INS (cfg->cbb, tls_get);
3917                 /* It is enough to reset the from field */
3918                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, MONO_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3919         }
3920 }
3921
3922 /*
3923  * On return the caller must check @array_class for load errors
3924  */
3925 static void
3926 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3927 {
3928         int vtable_reg = alloc_preg (cfg);
3929         int context_used;
3930
3931         context_used = mini_class_check_context_used (cfg, array_class);
3932
3933         save_cast_details (cfg, array_class, obj->dreg, FALSE);
3934
3935         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
3936
3937         if (cfg->opt & MONO_OPT_SHARED) {
3938                 int class_reg = alloc_preg (cfg);
3939                 MonoInst *ins;
3940
3941                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
3942                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_CLASS, array_class);
3943                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, ins->dreg);
3944         } else if (context_used) {
3945                 MonoInst *vtable_ins;
3946
3947                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3948                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3949         } else {
3950                 if (cfg->compile_aot) {
3951                         int vt_reg;
3952                         MonoVTable *vtable;
3953
3954                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3955                                 return;
3956                         vt_reg = alloc_preg (cfg);
3957                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3958                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3959                 } else {
3960                         MonoVTable *vtable;
3961                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3962                                 return;
3963                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3964                 }
3965         }
3966         
3967         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3968
3969         reset_cast_details (cfg);
3970 }
3971
3972 /**
3973  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3974  * generic code is generated.
3975  */
3976 static MonoInst*
3977 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3978 {
3979         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3980
3981         if (context_used) {
3982                 MonoInst *rgctx, *addr;
3983
3984                 /* FIXME: What if the class is shared?  We might not
3985                    have to get the address of the method from the
3986                    RGCTX. */
3987                 addr = emit_get_rgctx_method (cfg, context_used, method,
3988                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3989
3990                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3991
3992                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3993         } else {
3994                 gboolean pass_vtable, pass_mrgctx;
3995                 MonoInst *rgctx_arg = NULL;
3996
3997                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3998                 g_assert (!pass_mrgctx);
3999
4000                 if (pass_vtable) {
4001                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4002
4003                         g_assert (vtable);
4004                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4005                 }
4006
4007                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4008         }
4009 }
4010
4011 static MonoInst*
4012 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
4013 {
4014         MonoInst *add;
4015         int obj_reg;
4016         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
4017         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
4018         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
4019         int rank_reg = alloc_dreg (cfg ,STACK_I4);
4020
4021         obj_reg = sp [0]->dreg;
4022         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4023         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4024
4025         /* FIXME: generics */
4026         g_assert (klass->rank == 0);
4027                         
4028         // Check rank == 0
4029         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
4030         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4031
4032         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4033         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, element_class));
4034
4035         if (context_used) {
4036                 MonoInst *element_class;
4037
4038                 /* This assertion is from the unboxcast insn */
4039                 g_assert (klass->rank == 0);
4040
4041                 element_class = emit_get_rgctx_klass (cfg, context_used,
4042                                 klass, MONO_RGCTX_INFO_ELEMENT_KLASS);
4043
4044                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
4045                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4046         } else {
4047                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE);
4048                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
4049                 reset_cast_details (cfg);
4050         }
4051
4052         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
4053         MONO_ADD_INS (cfg->cbb, add);
4054         add->type = STACK_MP;
4055         add->klass = klass;
4056
4057         return add;
4058 }
4059
4060 static MonoInst*
4061 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj)
4062 {
4063         MonoInst *addr, *klass_inst, *is_ref, *args[16];
4064         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4065         MonoInst *ins;
4066         int dreg, addr_reg;
4067
4068         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
4069
4070         /* obj */
4071         args [0] = obj;
4072
4073         /* klass */
4074         args [1] = klass_inst;
4075
4076         /* CASTCLASS */
4077         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
4078
4079         NEW_BBLOCK (cfg, is_ref_bb);
4080         NEW_BBLOCK (cfg, is_nullable_bb);
4081         NEW_BBLOCK (cfg, end_bb);
4082         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4083         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4084         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4085
4086         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4087         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4088
4089         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
4090         addr_reg = alloc_dreg (cfg, STACK_MP);
4091
4092         /* Non-ref case */
4093         /* UNBOX */
4094         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
4095         MONO_ADD_INS (cfg->cbb, addr);
4096
4097         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4098
4099         /* Ref case */
4100         MONO_START_BB (cfg, is_ref_bb);
4101
4102         /* Save the ref to a temporary */
4103         dreg = alloc_ireg (cfg);
4104         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
4105         addr->dreg = addr_reg;
4106         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
4107         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4108
4109         /* Nullable case */
4110         MONO_START_BB (cfg, is_nullable_bb);
4111
4112         {
4113                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
4114                 MonoInst *unbox_call;
4115                 MonoMethodSignature *unbox_sig;
4116
4117                 unbox_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4118                 unbox_sig->ret = &klass->byval_arg;
4119                 unbox_sig->param_count = 1;
4120                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
4121                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
4122
4123                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
4124                 addr->dreg = addr_reg;
4125         }
4126
4127         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4128
4129         /* End */
4130         MONO_START_BB (cfg, end_bb);
4131
4132         /* LDOBJ */
4133         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
4134
4135         return ins;
4136 }
4137
4138 /*
4139  * Returns NULL and set the cfg exception on error.
4140  */
4141 static MonoInst*
4142 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
4143 {
4144         MonoInst *iargs [2];
4145         void *alloc_ftn;
4146
4147         if (context_used) {
4148                 MonoInst *data;
4149                 MonoRgctxInfoType rgctx_info;
4150                 MonoInst *iargs [2];
4151                 gboolean known_instance_size = !mini_is_gsharedvt_klass (klass);
4152
4153                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box, known_instance_size);
4154
4155                 if (cfg->opt & MONO_OPT_SHARED)
4156                         rgctx_info = MONO_RGCTX_INFO_KLASS;
4157                 else
4158                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
4159                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
4160
4161                 if (cfg->opt & MONO_OPT_SHARED) {
4162                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4163                         iargs [1] = data;
4164                         alloc_ftn = mono_object_new;
4165                 } else {
4166                         iargs [0] = data;
4167                         alloc_ftn = mono_object_new_specific;
4168                 }
4169
4170                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED)) {
4171                         if (known_instance_size) {
4172                                 int size = mono_class_instance_size (klass);
4173                                 if (size < sizeof (MonoObject))
4174                                         g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4175
4176                                 EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4177                         }
4178                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4179                 }
4180
4181                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4182         }
4183
4184         if (cfg->opt & MONO_OPT_SHARED) {
4185                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
4186                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
4187
4188                 alloc_ftn = mono_object_new;
4189         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
4190                 /* This happens often in argument checking code, eg. throw new FooException... */
4191                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
4192                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
4193                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
4194         } else {
4195                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
4196                 MonoMethod *managed_alloc = NULL;
4197                 gboolean pass_lw;
4198
4199                 if (!vtable) {
4200                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4201                         cfg->exception_ptr = klass;
4202                         return NULL;
4203                 }
4204
4205                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box, TRUE);
4206
4207                 if (managed_alloc) {
4208                         int size = mono_class_instance_size (klass);
4209                         if (size < sizeof (MonoObject))
4210                                 g_error ("Invalid size %d for class %s", size, mono_type_get_full_name (klass));
4211
4212                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4213                         EMIT_NEW_ICONST (cfg, iargs [1], mono_gc_get_aligned_size_for_allocator (size));
4214                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
4215                 }
4216                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
4217                 if (pass_lw) {
4218                         guint32 lw = vtable->klass->instance_size;
4219                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
4220                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
4221                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
4222                 }
4223                 else {
4224                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4225                 }
4226         }
4227
4228         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
4229 }
4230         
4231 /*
4232  * Returns NULL and set the cfg exception on error.
4233  */     
4234 static MonoInst*
4235 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
4236 {
4237         MonoInst *alloc, *ins;
4238
4239         if (mono_class_is_nullable (klass)) {
4240                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
4241
4242                 if (context_used) {
4243                         /* FIXME: What if the class is shared?  We might not
4244                            have to get the method address from the RGCTX. */
4245                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
4246                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
4247                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
4248
4249                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
4250                 } else {
4251                         gboolean pass_vtable, pass_mrgctx;
4252                         MonoInst *rgctx_arg = NULL;
4253
4254                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
4255                         g_assert (!pass_mrgctx);
4256
4257                         if (pass_vtable) {
4258                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4259
4260                                 g_assert (vtable);
4261                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
4262                         }
4263
4264                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
4265                 }
4266         }
4267
4268         if (mini_is_gsharedvt_klass (klass)) {
4269                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
4270                 MonoInst *res, *is_ref, *src_var, *addr;
4271                 int dreg;
4272
4273                 dreg = alloc_ireg (cfg);
4274
4275                 NEW_BBLOCK (cfg, is_ref_bb);
4276                 NEW_BBLOCK (cfg, is_nullable_bb);
4277                 NEW_BBLOCK (cfg, end_bb);
4278                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
4279                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
4280                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
4281
4282                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, MONO_GSHAREDVT_BOX_TYPE_NULLABLE);
4283                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
4284
4285                 /* Non-ref case */
4286                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4287                 if (!alloc)
4288                         return NULL;
4289                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4290                 ins->opcode = OP_STOREV_MEMBASE;
4291
4292                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
4293                 res->type = STACK_OBJ;
4294                 res->klass = klass;
4295                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4296                 
4297                 /* Ref case */
4298                 MONO_START_BB (cfg, is_ref_bb);
4299
4300                 /* val is a vtype, so has to load the value manually */
4301                 src_var = get_vreg_to_inst (cfg, val->dreg);
4302                 if (!src_var)
4303                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
4304                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
4305                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
4306                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4307
4308                 /* Nullable case */
4309                 MONO_START_BB (cfg, is_nullable_bb);
4310
4311                 {
4312                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
4313                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
4314                         MonoInst *box_call;
4315                         MonoMethodSignature *box_sig;
4316
4317                         /*
4318                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
4319                          * construct that method at JIT time, so have to do things by hand.
4320                          */
4321                         box_sig = (MonoMethodSignature *)mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
4322                         box_sig->ret = &mono_defaults.object_class->byval_arg;
4323                         box_sig->param_count = 1;
4324                         box_sig->params [0] = &klass->byval_arg;
4325                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
4326                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
4327                         res->type = STACK_OBJ;
4328                         res->klass = klass;
4329                 }
4330
4331                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4332
4333                 MONO_START_BB (cfg, end_bb);
4334
4335                 return res;
4336         } else {
4337                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
4338                 if (!alloc)
4339                         return NULL;
4340
4341                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
4342                 return alloc;
4343         }
4344 }
4345
4346 static gboolean
4347 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
4348 {
4349         int i;
4350         MonoGenericContainer *container;
4351         MonoGenericInst *ginst;
4352
4353         if (klass->generic_class) {
4354                 container = klass->generic_class->container_class->generic_container;
4355                 ginst = klass->generic_class->context.class_inst;
4356         } else if (klass->generic_container && context_used) {
4357                 container = klass->generic_container;
4358                 ginst = container->context.class_inst;
4359         } else {
4360                 return FALSE;
4361         }
4362
4363         for (i = 0; i < container->type_argc; ++i) {
4364                 MonoType *type;
4365                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
4366                         continue;
4367                 type = ginst->type_argv [i];
4368                 if (mini_type_is_reference (type))
4369                         return TRUE;
4370         }
4371         return FALSE;
4372 }
4373
4374 static GHashTable* direct_icall_type_hash;
4375
4376 static gboolean
4377 icall_is_direct_callable (MonoCompile *cfg, MonoMethod *cmethod)
4378 {
4379         /* LLVM on amd64 can't handle calls to non-32 bit addresses */
4380         if (!direct_icalls_enabled (cfg))
4381                 return FALSE;
4382
4383         /*
4384          * An icall is directly callable if it doesn't directly or indirectly call mono_raise_exception ().
4385          * Whitelist a few icalls for now.
4386          */
4387         if (!direct_icall_type_hash) {
4388                 GHashTable *h = g_hash_table_new (g_str_hash, g_str_equal);
4389
4390                 g_hash_table_insert (h, (char*)"Decimal", GUINT_TO_POINTER (1));
4391                 g_hash_table_insert (h, (char*)"Number", GUINT_TO_POINTER (1));
4392                 g_hash_table_insert (h, (char*)"Buffer", GUINT_TO_POINTER (1));
4393                 g_hash_table_insert (h, (char*)"Monitor", GUINT_TO_POINTER (1));
4394                 mono_memory_barrier ();
4395                 direct_icall_type_hash = h;
4396         }
4397
4398         if (cmethod->klass == mono_defaults.math_class)
4399                 return TRUE;
4400         /* No locking needed */
4401         if (cmethod->klass->image == mono_defaults.corlib && g_hash_table_lookup (direct_icall_type_hash, cmethod->klass->name))
4402                 return TRUE;
4403         return FALSE;
4404 }
4405
4406 #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)
4407
4408 static MonoInst*
4409 emit_castclass_with_cache (MonoCompile *cfg, MonoClass *klass, MonoInst **args)
4410 {
4411         MonoMethod *mono_castclass;
4412         MonoInst *res;
4413
4414         mono_castclass = mono_marshal_get_castclass_with_cache ();
4415
4416         save_cast_details (cfg, klass, args [0]->dreg, TRUE);
4417         res = mono_emit_method_call (cfg, mono_castclass, args, NULL);
4418         reset_cast_details (cfg);
4419
4420         return res;
4421 }
4422
4423 static int
4424 get_castclass_cache_idx (MonoCompile *cfg)
4425 {
4426         /* Each CASTCLASS_CACHE patch needs a unique index which identifies the call site */
4427         cfg->castclass_cache_index ++;
4428         return (cfg->method_index << 16) | cfg->castclass_cache_index;
4429 }
4430
4431 static MonoInst*
4432 emit_castclass_with_cache_nonshared (MonoCompile *cfg, MonoInst *obj, MonoClass *klass)
4433 {
4434         MonoInst *args [3];
4435         int idx;
4436
4437         /* obj */
4438         args [0] = obj;
4439
4440         /* klass */
4441         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
4442
4443         /* inline cache*/
4444         idx = get_castclass_cache_idx (cfg);
4445         args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
4446
4447         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
4448         return emit_castclass_with_cache (cfg, klass, args);
4449 }
4450
4451 /*
4452  * Returns NULL and set the cfg exception on error.
4453  */
4454 static MonoInst*
4455 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, guint8 *ip, int *inline_costs)
4456 {
4457         MonoBasicBlock *is_null_bb;
4458         int obj_reg = src->dreg;
4459         int vtable_reg = alloc_preg (cfg);
4460         int context_used;
4461         MonoInst *klass_inst = NULL, *res;
4462
4463         context_used = mini_class_check_context_used (cfg, klass);
4464
4465         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
4466                 res = emit_castclass_with_cache_nonshared (cfg, src, klass);
4467                 (*inline_costs) += 2;
4468                 return res;
4469         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
4470                 MonoMethod *mono_castclass;
4471                 MonoInst *iargs [1];
4472                 int costs;
4473
4474                 mono_castclass = mono_marshal_get_castclass (klass); 
4475                 iargs [0] = src;
4476                                 
4477                 save_cast_details (cfg, klass, src->dreg, TRUE);
4478                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
4479                                                            iargs, ip, cfg->real_offset, TRUE);
4480                 reset_cast_details (cfg);
4481                 CHECK_CFG_EXCEPTION;
4482                 g_assert (costs > 0);
4483                                 
4484                 cfg->real_offset += 5;
4485
4486                 (*inline_costs) += costs;
4487
4488                 return src;
4489         }
4490
4491         if (context_used) {
4492                 MonoInst *args [3];
4493
4494                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4495                         MonoInst *cache_ins;
4496
4497                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4498
4499                         /* obj */
4500                         args [0] = src;
4501
4502                         /* klass - it's the second element of the cache entry*/
4503                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4504
4505                         /* cache */
4506                         args [2] = cache_ins;
4507
4508                         return emit_castclass_with_cache (cfg, klass, args);
4509                 }
4510
4511                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4512         }
4513
4514         NEW_BBLOCK (cfg, is_null_bb);
4515
4516         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4517         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
4518
4519         save_cast_details (cfg, klass, obj_reg, FALSE);
4520
4521         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4522                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4523                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
4524         } else {
4525                 int klass_reg = alloc_preg (cfg);
4526
4527                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4528
4529                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4530                         /* the remoting code is broken, access the class for now */
4531                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4532                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4533                                 if (!vt) {
4534                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4535                                         cfg->exception_ptr = klass;
4536                                         return NULL;
4537                                 }
4538                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4539                         } else {
4540                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4541                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4542                         }
4543                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
4544                 } else {
4545                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4546                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
4547                 }
4548         }
4549
4550         MONO_START_BB (cfg, is_null_bb);
4551
4552         reset_cast_details (cfg);
4553
4554         return src;
4555
4556 exception_exit:
4557         return NULL;
4558 }
4559
4560 /*
4561  * Returns NULL and set the cfg exception on error.
4562  */
4563 static MonoInst*
4564 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
4565 {
4566         MonoInst *ins;
4567         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
4568         int obj_reg = src->dreg;
4569         int vtable_reg = alloc_preg (cfg);
4570         int res_reg = alloc_ireg_ref (cfg);
4571         MonoInst *klass_inst = NULL;
4572
4573         if (context_used) {
4574                 MonoInst *args [3];
4575
4576                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
4577                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
4578                         MonoInst *cache_ins;
4579
4580                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
4581
4582                         /* obj */
4583                         args [0] = src;
4584
4585                         /* klass - it's the second element of the cache entry*/
4586                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
4587
4588                         /* cache */
4589                         args [2] = cache_ins;
4590
4591                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
4592                 }
4593
4594                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
4595         }
4596
4597         NEW_BBLOCK (cfg, is_null_bb);
4598         NEW_BBLOCK (cfg, false_bb);
4599         NEW_BBLOCK (cfg, end_bb);
4600
4601         /* Do the assignment at the beginning, so the other assignment can be if converted */
4602         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
4603         ins->type = STACK_OBJ;
4604         ins->klass = klass;
4605
4606         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4607         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
4608
4609         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4610
4611         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4612                 g_assert (!context_used);
4613                 /* the is_null_bb target simply copies the input register to the output */
4614                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
4615         } else {
4616                 int klass_reg = alloc_preg (cfg);
4617
4618                 if (klass->rank) {
4619                         int rank_reg = alloc_preg (cfg);
4620                         int eclass_reg = alloc_preg (cfg);
4621
4622                         g_assert (!context_used);
4623                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
4624                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
4625                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4626                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4627                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, MONO_STRUCT_OFFSET (MonoClass, cast_class));
4628                         if (klass->cast_class == mono_defaults.object_class) {
4629                                 int parent_reg = alloc_preg (cfg);
4630                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, MONO_STRUCT_OFFSET (MonoClass, parent));
4631                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4632                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4633                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4634                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4635                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4636                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4637                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4638                         } else if (klass->cast_class == mono_defaults.enum_class) {
4639                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4640                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4641                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4642                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4643                         } else {
4644                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4645                                         /* Check that the object is a vector too */
4646                                         int bounds_reg = alloc_preg (cfg);
4647                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, MONO_STRUCT_OFFSET (MonoArray, bounds));
4648                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4649                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4650                                 }
4651
4652                                 /* the is_null_bb target simply copies the input register to the output */
4653                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4654                         }
4655                 } else if (mono_class_is_nullable (klass)) {
4656                         g_assert (!context_used);
4657                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4658                         /* the is_null_bb target simply copies the input register to the output */
4659                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4660                 } else {
4661                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4662                                 g_assert (!context_used);
4663                                 /* the remoting code is broken, access the class for now */
4664                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4665                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4666                                         if (!vt) {
4667                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4668                                                 cfg->exception_ptr = klass;
4669                                                 return NULL;
4670                                         }
4671                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4672                                 } else {
4673                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4674                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4675                                 }
4676                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4677                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4678                         } else {
4679                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4680                                 /* the is_null_bb target simply copies the input register to the output */
4681                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4682                         }
4683                 }
4684         }
4685
4686         MONO_START_BB (cfg, false_bb);
4687
4688         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4689         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4690
4691         MONO_START_BB (cfg, is_null_bb);
4692
4693         MONO_START_BB (cfg, end_bb);
4694
4695         return ins;
4696 }
4697
4698 static MonoInst*
4699 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4700 {
4701         /* This opcode takes as input an object reference and a class, and returns:
4702         0) if the object is an instance of the class,
4703         1) if the object is not instance of the class,
4704         2) if the object is a proxy whose type cannot be determined */
4705
4706         MonoInst *ins;
4707 #ifndef DISABLE_REMOTING
4708         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4709 #else
4710         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4711 #endif
4712         int obj_reg = src->dreg;
4713         int dreg = alloc_ireg (cfg);
4714         int tmp_reg;
4715 #ifndef DISABLE_REMOTING
4716         int klass_reg = alloc_preg (cfg);
4717 #endif
4718
4719         NEW_BBLOCK (cfg, true_bb);
4720         NEW_BBLOCK (cfg, false_bb);
4721         NEW_BBLOCK (cfg, end_bb);
4722 #ifndef DISABLE_REMOTING
4723         NEW_BBLOCK (cfg, false2_bb);
4724         NEW_BBLOCK (cfg, no_proxy_bb);
4725 #endif
4726
4727         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4728         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4729
4730         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4731 #ifndef DISABLE_REMOTING
4732                 NEW_BBLOCK (cfg, interface_fail_bb);
4733 #endif
4734
4735                 tmp_reg = alloc_preg (cfg);
4736                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4737 #ifndef DISABLE_REMOTING
4738                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4739                 MONO_START_BB (cfg, interface_fail_bb);
4740                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4741                 
4742                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4743
4744                 tmp_reg = alloc_preg (cfg);
4745                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4746                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4747                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4748 #else
4749                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4750 #endif
4751         } else {
4752 #ifndef DISABLE_REMOTING
4753                 tmp_reg = alloc_preg (cfg);
4754                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4755                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4756
4757                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4758                 tmp_reg = alloc_preg (cfg);
4759                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4760                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4761
4762                 tmp_reg = alloc_preg (cfg);             
4763                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4764                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4765                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4766                 
4767                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4768                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4769
4770                 MONO_START_BB (cfg, no_proxy_bb);
4771
4772                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4773 #else
4774                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4775 #endif
4776         }
4777
4778         MONO_START_BB (cfg, false_bb);
4779
4780         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4781         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4782
4783 #ifndef DISABLE_REMOTING
4784         MONO_START_BB (cfg, false2_bb);
4785
4786         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4787         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4788 #endif
4789
4790         MONO_START_BB (cfg, true_bb);
4791
4792         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4793
4794         MONO_START_BB (cfg, end_bb);
4795
4796         /* FIXME: */
4797         MONO_INST_NEW (cfg, ins, OP_ICONST);
4798         ins->dreg = dreg;
4799         ins->type = STACK_I4;
4800
4801         return ins;
4802 }
4803
4804 static MonoInst*
4805 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4806 {
4807         /* This opcode takes as input an object reference and a class, and returns:
4808         0) if the object is an instance of the class,
4809         1) if the object is a proxy whose type cannot be determined
4810         an InvalidCastException exception is thrown otherwhise*/
4811         
4812         MonoInst *ins;
4813 #ifndef DISABLE_REMOTING
4814         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4815 #else
4816         MonoBasicBlock *ok_result_bb;
4817 #endif
4818         int obj_reg = src->dreg;
4819         int dreg = alloc_ireg (cfg);
4820         int tmp_reg = alloc_preg (cfg);
4821
4822 #ifndef DISABLE_REMOTING
4823         int klass_reg = alloc_preg (cfg);
4824         NEW_BBLOCK (cfg, end_bb);
4825 #endif
4826
4827         NEW_BBLOCK (cfg, ok_result_bb);
4828
4829         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4830         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4831
4832         save_cast_details (cfg, klass, obj_reg, FALSE);
4833
4834         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4835 #ifndef DISABLE_REMOTING
4836                 NEW_BBLOCK (cfg, interface_fail_bb);
4837         
4838                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4839                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4840                 MONO_START_BB (cfg, interface_fail_bb);
4841                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4842
4843                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4844
4845                 tmp_reg = alloc_preg (cfg);             
4846                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4847                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4848                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4849                 
4850                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4851                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4852 #else
4853                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4854                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4855                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4856 #endif
4857         } else {
4858 #ifndef DISABLE_REMOTING
4859                 NEW_BBLOCK (cfg, no_proxy_bb);
4860
4861                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoObject, vtable));
4862                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
4863                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4864
4865                 tmp_reg = alloc_preg (cfg);
4866                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4867                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, MONO_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4868
4869                 tmp_reg = alloc_preg (cfg);
4870                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, MONO_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4871                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4872                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4873
4874                 NEW_BBLOCK (cfg, fail_1_bb);
4875                 
4876                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4877
4878                 MONO_START_BB (cfg, fail_1_bb);
4879
4880                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4881                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4882
4883                 MONO_START_BB (cfg, no_proxy_bb);
4884
4885                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4886 #else
4887                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4888 #endif
4889         }
4890
4891         MONO_START_BB (cfg, ok_result_bb);
4892
4893         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4894
4895 #ifndef DISABLE_REMOTING
4896         MONO_START_BB (cfg, end_bb);
4897 #endif
4898
4899         /* FIXME: */
4900         MONO_INST_NEW (cfg, ins, OP_ICONST);
4901         ins->dreg = dreg;
4902         ins->type = STACK_I4;
4903
4904         return ins;
4905 }
4906
4907 static G_GNUC_UNUSED MonoInst*
4908 handle_enum_has_flag (MonoCompile *cfg, MonoClass *klass, MonoInst *enum_this, MonoInst *enum_flag)
4909 {
4910         MonoType *enum_type = mono_type_get_underlying_type (&klass->byval_arg);
4911         guint32 load_opc = mono_type_to_load_membase (cfg, enum_type);
4912         gboolean is_i4;
4913
4914         switch (enum_type->type) {
4915         case MONO_TYPE_I8:
4916         case MONO_TYPE_U8:
4917 #if SIZEOF_REGISTER == 8
4918         case MONO_TYPE_I:
4919         case MONO_TYPE_U:
4920 #endif
4921                 is_i4 = FALSE;
4922                 break;
4923         default:
4924                 is_i4 = TRUE;
4925                 break;
4926         }
4927
4928         {
4929                 MonoInst *load, *and_, *cmp, *ceq;
4930                 int enum_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4931                 int and_reg = is_i4 ? alloc_ireg (cfg) : alloc_lreg (cfg);
4932                 int dest_reg = alloc_ireg (cfg);
4933
4934                 EMIT_NEW_LOAD_MEMBASE (cfg, load, load_opc, enum_reg, enum_this->dreg, 0);
4935                 EMIT_NEW_BIALU (cfg, and_, is_i4 ? OP_IAND : OP_LAND, and_reg, enum_reg, enum_flag->dreg);
4936                 EMIT_NEW_BIALU (cfg, cmp, is_i4 ? OP_ICOMPARE : OP_LCOMPARE, -1, and_reg, enum_flag->dreg);
4937                 EMIT_NEW_UNALU (cfg, ceq, is_i4 ? OP_ICEQ : OP_LCEQ, dest_reg, -1);
4938
4939                 ceq->type = STACK_I4;
4940
4941                 if (!is_i4) {
4942                         load = mono_decompose_opcode (cfg, load);
4943                         and_ = mono_decompose_opcode (cfg, and_);
4944                         cmp = mono_decompose_opcode (cfg, cmp);
4945                         ceq = mono_decompose_opcode (cfg, ceq);
4946                 }
4947
4948                 return ceq;
4949         }
4950 }
4951
4952 /*
4953  * Returns NULL and set the cfg exception on error.
4954  */
4955 static G_GNUC_UNUSED MonoInst*
4956 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used, gboolean virtual_)
4957 {
4958         MonoInst *ptr;
4959         int dreg;
4960         gpointer trampoline;
4961         MonoInst *obj, *method_ins, *tramp_ins;
4962         MonoDomain *domain;
4963         guint8 **code_slot;
4964
4965         if (virtual_ && !cfg->llvm_only) {
4966                 MonoMethod *invoke = mono_get_delegate_invoke (klass);
4967                 g_assert (invoke);
4968
4969                 if (!mono_get_delegate_virtual_invoke_impl (mono_method_signature (invoke), context_used ? NULL : method))
4970                         return NULL;
4971         }
4972
4973         obj = handle_alloc (cfg, klass, FALSE, mono_class_check_context_used (klass));
4974         if (!obj)
4975                 return NULL;
4976
4977         if (cfg->llvm_only) {
4978                 MonoInst *args [16];
4979
4980                 /*
4981                  * If the method to be called needs an rgctx, we can't fall back to mono_delegate_ctor (), since it might receive
4982                  * the address of a gshared method. So use a JIT icall.
4983                  * FIXME: Optimize this.
4984                  */
4985                 args [0] = obj;
4986                 args [1] = target;
4987                 args [2] = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4988                 mono_emit_jit_icall (cfg, virtual_ ? mono_init_delegate_virtual : mono_init_delegate, args);
4989
4990                 return obj;
4991         }
4992
4993         /* Inline the contents of mono_delegate_ctor */
4994
4995         /* Set target field */
4996         /* Optimize away setting of NULL target */
4997         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4998                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4999                 if (cfg->gen_write_barriers) {
5000                         dreg = alloc_preg (cfg);
5001                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, target));
5002                         emit_write_barrier (cfg, ptr, target);
5003                 }
5004         }
5005
5006         /* Set method field */
5007         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
5008         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
5009
5010         /* 
5011          * To avoid looking up the compiled code belonging to the target method
5012          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
5013          * store it, and we fill it after the method has been compiled.
5014          */
5015         if (!method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
5016                 MonoInst *code_slot_ins;
5017
5018                 if (context_used) {
5019                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
5020                 } else {
5021                         domain = mono_domain_get ();
5022                         mono_domain_lock (domain);
5023                         if (!domain_jit_info (domain)->method_code_hash)
5024                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
5025                         code_slot = (guint8 **)g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
5026                         if (!code_slot) {
5027                                 code_slot = (guint8 **)mono_domain_alloc0 (domain, sizeof (gpointer));
5028                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
5029                         }
5030                         mono_domain_unlock (domain);
5031
5032                         code_slot_ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_METHOD_CODE_SLOT, method);
5033                 }
5034                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);                
5035         }
5036
5037         if (cfg->compile_aot) {
5038                 MonoDelegateClassMethodPair *del_tramp;
5039
5040                 del_tramp = (MonoDelegateClassMethodPair *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoDelegateClassMethodPair));
5041                 del_tramp->klass = klass;
5042                 del_tramp->method = context_used ? NULL : method;
5043                 del_tramp->is_virtual = virtual_;
5044                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, del_tramp);
5045         } else {
5046                 if (virtual_)
5047                         trampoline = mono_create_delegate_virtual_trampoline (cfg->domain, klass, context_used ? NULL : method);
5048                 else
5049                         trampoline = mono_create_delegate_trampoline_info (cfg->domain, klass, context_used ? NULL : method);
5050                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
5051         }
5052
5053         /* Set invoke_impl field */
5054         if (virtual_) {
5055                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
5056         } else {
5057                 dreg = alloc_preg (cfg);
5058                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, invoke_impl));
5059                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, invoke_impl), dreg);
5060
5061                 dreg = alloc_preg (cfg);
5062                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, tramp_ins->dreg, MONO_STRUCT_OFFSET (MonoDelegateTrampInfo, method_ptr));
5063                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_ptr), dreg);
5064         }
5065
5066         dreg = alloc_preg (cfg);
5067         MONO_EMIT_NEW_ICONST (cfg, dreg, virtual_ ? 1 : 0);
5068         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, obj->dreg, MONO_STRUCT_OFFSET (MonoDelegate, method_is_virtual), dreg);
5069
5070         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
5071
5072         return obj;
5073 }
5074
5075 static MonoInst*
5076 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
5077 {
5078         MonoJitICallInfo *info;
5079
5080         /* Need to register the icall so it gets an icall wrapper */
5081         info = mono_get_array_new_va_icall (rank);
5082
5083         cfg->flags |= MONO_CFG_HAS_VARARGS;
5084
5085         /* mono_array_new_va () needs a vararg calling convention */
5086         cfg->disable_llvm = TRUE;
5087
5088         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
5089         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
5090 }
5091
5092 /*
5093  * handle_constrained_gsharedvt_call:
5094  *
5095  *   Handle constrained calls where the receiver is a gsharedvt type.
5096  * Return the instruction representing the call. Set the cfg exception on failure.
5097  */
5098 static MonoInst*
5099 handle_constrained_gsharedvt_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp, MonoClass *constrained_class,
5100                                                                    gboolean *ref_emit_widen)
5101 {
5102         MonoInst *ins = NULL;
5103         gboolean emit_widen = *ref_emit_widen;
5104
5105         /*
5106          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
5107          * This is hard to do with the current call code, since we would have to emit a branch and two different calls. So instead, we
5108          * pack the arguments into an array, and do the rest of the work in in an icall.
5109          */
5110         if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
5111                 (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 (fsig->ret)) &&
5112                 (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || fsig->params [0]->byref || mini_is_gsharedvt_type (fsig->params [0]))))) {
5113                 MonoInst *args [16];
5114
5115                 /*
5116                  * This case handles calls to
5117                  * - object:ToString()/Equals()/GetHashCode(),
5118                  * - System.IComparable<T>:CompareTo()
5119                  * - System.IEquatable<T>:Equals ()
5120                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
5121                  */
5122
5123                 args [0] = sp [0];
5124                 if (mono_method_check_context_used (cmethod))
5125                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
5126                 else
5127                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
5128                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_class), constrained_class, MONO_RGCTX_INFO_KLASS);
5129
5130                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
5131                 if (fsig->hasthis && fsig->param_count) {
5132                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
5133                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
5134                         ins->dreg = alloc_preg (cfg);
5135                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
5136                         MONO_ADD_INS (cfg->cbb, ins);
5137                         args [4] = ins;
5138
5139                         if (mini_is_gsharedvt_type (fsig->params [0])) {
5140                                 int addr_reg, deref_arg_reg;
5141
5142                                 ins = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
5143                                 deref_arg_reg = alloc_preg (cfg);
5144                                 /* deref_arg = BOX_TYPE != MONO_GSHAREDVT_BOX_TYPE_VTYPE */
5145                                 EMIT_NEW_BIALU_IMM (cfg, args [3], OP_ISUB_IMM, deref_arg_reg, ins->dreg, 1);
5146
5147                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
5148                                 addr_reg = ins->dreg;
5149                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
5150                         } else {
5151                                 EMIT_NEW_ICONST (cfg, args [3], 0);
5152                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
5153                         }
5154                 } else {
5155                         EMIT_NEW_ICONST (cfg, args [3], 0);
5156                         EMIT_NEW_ICONST (cfg, args [4], 0);
5157                 }
5158                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
5159                 emit_widen = FALSE;
5160
5161                 if (mini_is_gsharedvt_type (fsig->ret)) {
5162                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins);
5163                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_ISSTRUCT (fsig->ret)) {
5164                         MonoInst *add;
5165
5166                         /* Unbox */
5167                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
5168                         MONO_ADD_INS (cfg->cbb, add);
5169                         /* Load value */
5170                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
5171                         MONO_ADD_INS (cfg->cbb, ins);
5172                         /* ins represents the call result */
5173                 }
5174         } else {
5175                 GSHAREDVT_FAILURE (CEE_CALLVIRT);
5176         }
5177
5178         *ref_emit_widen = emit_widen;
5179
5180         return ins;
5181
5182  exception_exit:
5183         return NULL;
5184 }
5185
5186 static void
5187 mono_emit_load_got_addr (MonoCompile *cfg)
5188 {
5189         MonoInst *getaddr, *dummy_use;
5190
5191         if (!cfg->got_var || cfg->got_var_allocated)
5192                 return;
5193
5194         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
5195         getaddr->cil_code = cfg->header->code;
5196         getaddr->dreg = cfg->got_var->dreg;
5197
5198         /* Add it to the start of the first bblock */
5199         if (cfg->bb_entry->code) {
5200                 getaddr->next = cfg->bb_entry->code;
5201                 cfg->bb_entry->code = getaddr;
5202         }
5203         else
5204                 MONO_ADD_INS (cfg->bb_entry, getaddr);
5205
5206         cfg->got_var_allocated = TRUE;
5207
5208         /* 
5209          * Add a dummy use to keep the got_var alive, since real uses might
5210          * only be generated by the back ends.
5211          * Add it to end_bblock, so the variable's lifetime covers the whole
5212          * method.
5213          * It would be better to make the usage of the got var explicit in all
5214          * cases when the backend needs it (i.e. calls, throw etc.), so this
5215          * wouldn't be needed.
5216          */
5217         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
5218         MONO_ADD_INS (cfg->bb_exit, dummy_use);
5219 }
5220
5221 static int inline_limit;
5222 static gboolean inline_limit_inited;
5223
5224 static gboolean
5225 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
5226 {
5227         MonoMethodHeaderSummary header;
5228         MonoVTable *vtable;
5229 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5230         MonoMethodSignature *sig = mono_method_signature (method);
5231         int i;
5232 #endif
5233
5234         if (cfg->disable_inline)
5235                 return FALSE;
5236         if (cfg->gshared)
5237                 return FALSE;
5238
5239         if (cfg->inline_depth > 10)
5240                 return FALSE;
5241
5242         if (!mono_method_get_header_summary (method, &header))
5243                 return FALSE;
5244
5245         /*runtime, icall and pinvoke are checked by summary call*/
5246         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
5247             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
5248             (mono_class_is_marshalbyref (method->klass)) ||
5249             header.has_clauses)
5250                 return FALSE;
5251
5252         /* also consider num_locals? */
5253         /* Do the size check early to avoid creating vtables */
5254         if (!inline_limit_inited) {
5255                 if (g_getenv ("MONO_INLINELIMIT"))
5256                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
5257                 else
5258                         inline_limit = INLINE_LENGTH_LIMIT;
5259                 inline_limit_inited = TRUE;
5260         }
5261         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
5262                 return FALSE;
5263
5264         /*
5265          * if we can initialize the class of the method right away, we do,
5266          * otherwise we don't allow inlining if the class needs initialization,
5267          * since it would mean inserting a call to mono_runtime_class_init()
5268          * inside the inlined code
5269          */
5270         if (!(cfg->opt & MONO_OPT_SHARED)) {
5271                 /* The AggressiveInlining hint is a good excuse to force that cctor to run. */
5272                 if (method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING) {
5273                         vtable = mono_class_vtable (cfg->domain, method->klass);
5274                         if (!vtable)
5275                                 return FALSE;
5276                         if (!cfg->compile_aot)
5277                                 mono_runtime_class_init (vtable);
5278                 } else if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5279                         if (cfg->run_cctors && method->klass->has_cctor) {
5280                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
5281                                 if (!method->klass->runtime_info)
5282                                         /* No vtable created yet */
5283                                         return FALSE;
5284                                 vtable = mono_class_vtable (cfg->domain, method->klass);
5285                                 if (!vtable)
5286                                         return FALSE;
5287                                 /* This makes so that inline cannot trigger */
5288                                 /* .cctors: too many apps depend on them */
5289                                 /* running with a specific order... */
5290                                 if (! vtable->initialized)
5291                                         return FALSE;
5292                                 mono_runtime_class_init (vtable);
5293                         }
5294                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
5295                         if (!method->klass->runtime_info)
5296                                 /* No vtable created yet */
5297                                 return FALSE;
5298                         vtable = mono_class_vtable (cfg->domain, method->klass);
5299                         if (!vtable)
5300                                 return FALSE;
5301                         if (!vtable->initialized)
5302                                 return FALSE;
5303                 }
5304         } else {
5305                 /* 
5306                  * If we're compiling for shared code
5307                  * the cctor will need to be run at aot method load time, for example,
5308                  * or at the end of the compilation of the inlining method.
5309                  */
5310                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
5311                         return FALSE;
5312         }
5313
5314 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
5315         if (mono_arch_is_soft_float ()) {
5316                 /* FIXME: */
5317                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
5318                         return FALSE;
5319                 for (i = 0; i < sig->param_count; ++i)
5320                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
5321                                 return FALSE;
5322         }
5323 #endif
5324
5325         if (g_list_find (cfg->dont_inline, method))
5326                 return FALSE;
5327
5328         return TRUE;
5329 }
5330
5331 static gboolean
5332 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
5333 {
5334         if (!cfg->compile_aot) {
5335                 g_assert (vtable);
5336                 if (vtable->initialized)
5337                         return FALSE;
5338         }
5339
5340         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
5341                 if (cfg->method == method)
5342                         return FALSE;
5343         }
5344
5345         if (!mono_class_needs_cctor_run (klass, method))
5346                 return FALSE;
5347
5348         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
5349                 /* The initialization is already done before the method is called */
5350                 return FALSE;
5351
5352         return TRUE;
5353 }
5354
5355 static MonoInst*
5356 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
5357 {
5358         MonoInst *ins;
5359         guint32 size;
5360         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
5361         int context_used;
5362
5363         if (mini_is_gsharedvt_variable_klass (klass)) {
5364                 size = -1;
5365         } else {
5366                 mono_class_init (klass);
5367                 size = mono_class_array_element_size (klass);
5368         }
5369
5370         mult_reg = alloc_preg (cfg);
5371         array_reg = arr->dreg;
5372         index_reg = index->dreg;
5373
5374 #if SIZEOF_REGISTER == 8
5375         /* The array reg is 64 bits but the index reg is only 32 */
5376         if (COMPILE_LLVM (cfg)) {
5377                 /* Not needed */
5378                 index2_reg = index_reg;
5379         } else {
5380                 index2_reg = alloc_preg (cfg);
5381                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
5382         }
5383 #else
5384         if (index->type == STACK_I8) {
5385                 index2_reg = alloc_preg (cfg);
5386                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
5387         } else {
5388                 index2_reg = index_reg;
5389         }
5390 #endif
5391
5392         if (bcheck)
5393                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
5394
5395 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5396         if (size == 1 || size == 2 || size == 4 || size == 8) {
5397                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
5398
5399                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], MONO_STRUCT_OFFSET (MonoArray, vector));
5400                 ins->klass = mono_class_get_element_class (klass);
5401                 ins->type = STACK_MP;
5402
5403                 return ins;
5404         }
5405 #endif          
5406
5407         add_reg = alloc_ireg_mp (cfg);
5408
5409         if (size == -1) {
5410                 MonoInst *rgctx_ins;
5411
5412                 /* gsharedvt */
5413                 g_assert (cfg->gshared);
5414                 context_used = mini_class_check_context_used (cfg, klass);
5415                 g_assert (context_used);
5416                 rgctx_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
5417                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
5418         } else {
5419                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
5420         }
5421         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
5422         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5423         ins->klass = mono_class_get_element_class (klass);
5424         ins->type = STACK_MP;
5425         MONO_ADD_INS (cfg->cbb, ins);
5426
5427         return ins;
5428 }
5429
5430 static MonoInst*
5431 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
5432 {
5433         int bounds_reg = alloc_preg (cfg);
5434         int add_reg = alloc_ireg_mp (cfg);
5435         int mult_reg = alloc_preg (cfg);
5436         int mult2_reg = alloc_preg (cfg);
5437         int low1_reg = alloc_preg (cfg);
5438         int low2_reg = alloc_preg (cfg);
5439         int high1_reg = alloc_preg (cfg);
5440         int high2_reg = alloc_preg (cfg);
5441         int realidx1_reg = alloc_preg (cfg);
5442         int realidx2_reg = alloc_preg (cfg);
5443         int sum_reg = alloc_preg (cfg);
5444         int index1, index2, tmpreg;
5445         MonoInst *ins;
5446         guint32 size;
5447
5448         mono_class_init (klass);
5449         size = mono_class_array_element_size (klass);
5450
5451         index1 = index_ins1->dreg;
5452         index2 = index_ins2->dreg;
5453
5454 #if SIZEOF_REGISTER == 8
5455         /* The array reg is 64 bits but the index reg is only 32 */
5456         if (COMPILE_LLVM (cfg)) {
5457                 /* Not needed */
5458         } else {
5459                 tmpreg = alloc_preg (cfg);
5460                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
5461                 index1 = tmpreg;
5462                 tmpreg = alloc_preg (cfg);
5463                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
5464                 index2 = tmpreg;
5465         }
5466 #else
5467         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
5468         tmpreg = -1;
5469 #endif
5470
5471         /* range checking */
5472         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
5473                                        arr->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5474
5475         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
5476                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5477         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
5478         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
5479                                        bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5480         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
5481         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5482
5483         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
5484                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5485         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
5486         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
5487                                        bounds_reg, sizeof (MonoArrayBounds) + MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5488         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
5489         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
5490
5491         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
5492         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
5493         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
5494         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
5495         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, MONO_STRUCT_OFFSET (MonoArray, vector));
5496
5497         ins->type = STACK_MP;
5498         ins->klass = klass;
5499         MONO_ADD_INS (cfg->cbb, ins);
5500
5501         return ins;
5502 }
5503
5504 static MonoInst*
5505 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
5506 {
5507         int rank;
5508         MonoInst *addr;
5509         MonoMethod *addr_method;
5510         int element_size;
5511         MonoClass *eclass = cmethod->klass->element_class;
5512
5513         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
5514
5515         if (rank == 1)
5516                 return mini_emit_ldelema_1_ins (cfg, eclass, sp [0], sp [1], TRUE);
5517
5518         /* emit_ldelema_2 depends on OP_LMUL */
5519         if (!cfg->backend->emulate_mul_div && rank == 2 && (cfg->opt & MONO_OPT_INTRINS) && !mini_is_gsharedvt_variable_klass (eclass)) {
5520                 return mini_emit_ldelema_2_ins (cfg, eclass, sp [0], sp [1], sp [2]);
5521         }
5522
5523         if (mini_is_gsharedvt_variable_klass (eclass))
5524                 element_size = 0;
5525         else
5526                 element_size = mono_class_array_element_size (eclass);
5527         addr_method = mono_marshal_get_array_address (rank, element_size);
5528         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
5529
5530         return addr;
5531 }
5532
5533 static MonoBreakPolicy
5534 always_insert_breakpoint (MonoMethod *method)
5535 {
5536         return MONO_BREAK_POLICY_ALWAYS;
5537 }
5538
5539 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
5540
5541 /**
5542  * mono_set_break_policy:
5543  * policy_callback: the new callback function
5544  *
5545  * Allow embedders to decide wherther to actually obey breakpoint instructions
5546  * (both break IL instructions and Debugger.Break () method calls), for example
5547  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
5548  * untrusted or semi-trusted code.
5549  *
5550  * @policy_callback will be called every time a break point instruction needs to
5551  * be inserted with the method argument being the method that calls Debugger.Break()
5552  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
5553  * if it wants the breakpoint to not be effective in the given method.
5554  * #MONO_BREAK_POLICY_ALWAYS is the default.
5555  */
5556 void
5557 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
5558 {
5559         if (policy_callback)
5560                 break_policy_func = policy_callback;
5561         else
5562                 break_policy_func = always_insert_breakpoint;
5563 }
5564
5565 static gboolean
5566 should_insert_brekpoint (MonoMethod *method) {
5567         switch (break_policy_func (method)) {
5568         case MONO_BREAK_POLICY_ALWAYS:
5569                 return TRUE;
5570         case MONO_BREAK_POLICY_NEVER:
5571                 return FALSE;
5572         case MONO_BREAK_POLICY_ON_DBG:
5573                 g_warning ("mdb no longer supported");
5574                 return FALSE;
5575         default:
5576                 g_warning ("Incorrect value returned from break policy callback");
5577                 return FALSE;
5578         }
5579 }
5580
5581 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
5582 static MonoInst*
5583 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5584 {
5585         MonoInst *addr, *store, *load;
5586         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
5587
5588         /* the bounds check is already done by the callers */
5589         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5590         if (is_set) {
5591                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
5592                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
5593                 if (mini_type_is_reference (fsig->params [2]))
5594                         emit_write_barrier (cfg, addr, load);
5595         } else {
5596                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
5597                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
5598         }
5599         return store;
5600 }
5601
5602
5603 static gboolean
5604 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5605 {
5606         return mini_type_is_reference (&klass->byval_arg);
5607 }
5608
5609 static MonoInst*
5610 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
5611 {
5612         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
5613                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
5614                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
5615                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
5616                 MonoInst *iargs [3];
5617
5618                 if (!helper->slot)
5619                         mono_class_setup_vtable (obj_array);
5620                 g_assert (helper->slot);
5621
5622                 if (sp [0]->type != STACK_OBJ)
5623                         return NULL;
5624                 if (sp [2]->type != STACK_OBJ)
5625                         return NULL;
5626
5627                 iargs [2] = sp [2];
5628                 iargs [1] = sp [1];
5629                 iargs [0] = sp [0];
5630
5631                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
5632         } else {
5633                 MonoInst *ins;
5634
5635                 if (mini_is_gsharedvt_variable_klass (klass)) {
5636                         MonoInst *addr;
5637
5638                         // FIXME-VT: OP_ICONST optimization
5639                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
5640                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5641                         ins->opcode = OP_STOREV_MEMBASE;
5642                 } else if (sp [1]->opcode == OP_ICONST) {
5643                         int array_reg = sp [0]->dreg;
5644                         int index_reg = sp [1]->dreg;
5645                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
5646
5647                         if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
5648                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
5649
5650                         if (safety_checks)
5651                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
5652                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
5653                 } else {
5654                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
5655                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
5656                         if (generic_class_is_reference_type (cfg, klass))
5657                                 emit_write_barrier (cfg, addr, sp [2]);
5658                 }
5659                 return ins;
5660         }
5661 }
5662
5663 static MonoInst*
5664 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
5665 {
5666         MonoClass *eklass;
5667         
5668         if (is_set)
5669                 eklass = mono_class_from_mono_type (fsig->params [2]);
5670         else
5671                 eklass = mono_class_from_mono_type (fsig->ret);
5672
5673         if (is_set) {
5674                 return emit_array_store (cfg, eklass, args, FALSE);
5675         } else {
5676                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
5677                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
5678                 return ins;
5679         }
5680 }
5681
5682 static gboolean
5683 is_unsafe_mov_compatible (MonoCompile *cfg, MonoClass *param_klass, MonoClass *return_klass)
5684 {
5685         uint32_t align;
5686         int param_size, return_size;
5687
5688         param_klass = mono_class_from_mono_type (mini_get_underlying_type (&param_klass->byval_arg));
5689         return_klass = mono_class_from_mono_type (mini_get_underlying_type (&return_klass->byval_arg));
5690
5691         if (cfg->verbose_level > 3)
5692                 printf ("[UNSAFE-MOV-INTRISIC] %s <- %s\n", return_klass->name, param_klass->name);
5693
5694         //Don't allow mixing reference types with value types
5695         if (param_klass->valuetype != return_klass->valuetype) {
5696                 if (cfg->verbose_level > 3)
5697                         printf ("[UNSAFE-MOV-INTRISIC]\tone of the args is a valuetype and the other is not\n");
5698                 return FALSE;
5699         }
5700
5701         if (!param_klass->valuetype) {
5702                 if (cfg->verbose_level > 3)
5703                         printf ("[UNSAFE-MOV-INTRISIC]\targs are reference types\n");
5704                 return TRUE;
5705         }
5706
5707         //That are blitable
5708         if (param_klass->has_references || return_klass->has_references)
5709                 return FALSE;
5710
5711         /* Avoid mixing structs and primitive types/enums, they need to be handled differently in the JIT */
5712         if ((MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && !MONO_TYPE_ISSTRUCT (&return_klass->byval_arg)) ||
5713                 (!MONO_TYPE_ISSTRUCT (&param_klass->byval_arg) && MONO_TYPE_ISSTRUCT (&return_klass->byval_arg))) {
5714                         if (cfg->verbose_level > 3)
5715                                 printf ("[UNSAFE-MOV-INTRISIC]\tmixing structs and scalars\n");
5716                 return FALSE;
5717         }
5718
5719         if (param_klass->byval_arg.type == MONO_TYPE_R4 || param_klass->byval_arg.type == MONO_TYPE_R8 ||
5720                 return_klass->byval_arg.type == MONO_TYPE_R4 || return_klass->byval_arg.type == MONO_TYPE_R8) {
5721                 if (cfg->verbose_level > 3)
5722                         printf ("[UNSAFE-MOV-INTRISIC]\tfloat or double are not supported\n");
5723                 return FALSE;
5724         }
5725
5726         param_size = mono_class_value_size (param_klass, &align);
5727         return_size = mono_class_value_size (return_klass, &align);
5728
5729         //We can do it if sizes match
5730         if (param_size == return_size) {
5731                 if (cfg->verbose_level > 3)
5732                         printf ("[UNSAFE-MOV-INTRISIC]\tsame size\n");
5733                 return TRUE;
5734         }
5735
5736         //No simple way to handle struct if sizes don't match
5737         if (MONO_TYPE_ISSTRUCT (&param_klass->byval_arg)) {
5738                 if (cfg->verbose_level > 3)
5739                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch and type is a struct\n");
5740                 return FALSE;
5741         }
5742
5743         /*
5744          * Same reg size category.
5745          * A quick note on why we don't require widening here.
5746          * The intrinsic is "R Array.UnsafeMov<S,R> (S s)".
5747          *
5748          * Since the source value comes from a function argument, the JIT will already have
5749          * the value in a VREG and performed any widening needed before (say, when loading from a field).
5750          */
5751         if (param_size <= 4 && return_size <= 4) {
5752                 if (cfg->verbose_level > 3)
5753                         printf ("[UNSAFE-MOV-INTRISIC]\tsize mismatch but both are of the same reg class\n");
5754                 return TRUE;
5755         }
5756
5757         return FALSE;
5758 }
5759
5760 static MonoInst*
5761 emit_array_unsafe_mov (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args)
5762 {
5763         MonoClass *param_klass = mono_class_from_mono_type (fsig->params [0]);
5764         MonoClass *return_klass = mono_class_from_mono_type (fsig->ret);
5765
5766         if (mini_is_gsharedvt_variable_type (fsig->ret))
5767                 return NULL;
5768
5769         //Valuetypes that are semantically equivalent or numbers than can be widened to
5770         if (is_unsafe_mov_compatible (cfg, param_klass, return_klass))
5771                 return args [0];
5772
5773         //Arrays of valuetypes that are semantically equivalent
5774         if (param_klass->rank == 1 && return_klass->rank == 1 && is_unsafe_mov_compatible (cfg, param_klass->element_class, return_klass->element_class))
5775                 return args [0];
5776
5777         return NULL;
5778 }
5779
5780 static MonoInst*
5781 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5782 {
5783 #ifdef MONO_ARCH_SIMD_INTRINSICS
5784         MonoInst *ins = NULL;
5785
5786         if (cfg->opt & MONO_OPT_SIMD) {
5787                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5788                 if (ins)
5789                         return ins;
5790         }
5791 #endif
5792
5793         return mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
5794 }
5795
5796 static MonoInst*
5797 emit_memory_barrier (MonoCompile *cfg, int kind)
5798 {
5799         MonoInst *ins = NULL;
5800         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
5801         MONO_ADD_INS (cfg->cbb, ins);
5802         ins->backend.memory_barrier_kind = kind;
5803
5804         return ins;
5805 }
5806
5807 static MonoInst*
5808 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5809 {
5810         MonoInst *ins = NULL;
5811         int opcode = 0;
5812
5813         /* The LLVM backend supports these intrinsics */
5814         if (cmethod->klass == mono_defaults.math_class) {
5815                 if (strcmp (cmethod->name, "Sin") == 0) {
5816                         opcode = OP_SIN;
5817                 } else if (strcmp (cmethod->name, "Cos") == 0) {
5818                         opcode = OP_COS;
5819                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
5820                         opcode = OP_SQRT;
5821                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
5822                         opcode = OP_ABS;
5823                 }
5824
5825                 if (opcode && fsig->param_count == 1) {
5826                         MONO_INST_NEW (cfg, ins, opcode);
5827                         ins->type = STACK_R8;
5828                         ins->dreg = mono_alloc_freg (cfg);
5829                         ins->sreg1 = args [0]->dreg;
5830                         MONO_ADD_INS (cfg->cbb, ins);
5831                 }
5832
5833                 opcode = 0;
5834                 if (cfg->opt & MONO_OPT_CMOV) {
5835                         if (strcmp (cmethod->name, "Min") == 0) {
5836                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5837                                         opcode = OP_IMIN;
5838                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5839                                         opcode = OP_IMIN_UN;
5840                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5841                                         opcode = OP_LMIN;
5842                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5843                                         opcode = OP_LMIN_UN;
5844                         } else if (strcmp (cmethod->name, "Max") == 0) {
5845                                 if (fsig->params [0]->type == MONO_TYPE_I4)
5846                                         opcode = OP_IMAX;
5847                                 if (fsig->params [0]->type == MONO_TYPE_U4)
5848                                         opcode = OP_IMAX_UN;
5849                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
5850                                         opcode = OP_LMAX;
5851                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
5852                                         opcode = OP_LMAX_UN;
5853                         }
5854                 }
5855
5856                 if (opcode && fsig->param_count == 2) {
5857                         MONO_INST_NEW (cfg, ins, opcode);
5858                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
5859                         ins->dreg = mono_alloc_ireg (cfg);
5860                         ins->sreg1 = args [0]->dreg;
5861                         ins->sreg2 = args [1]->dreg;
5862                         MONO_ADD_INS (cfg->cbb, ins);
5863                 }
5864         }
5865
5866         return ins;
5867 }
5868
5869 static MonoInst*
5870 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5871 {
5872         if (cmethod->klass == mono_defaults.array_class) {
5873                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
5874                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
5875                 else if (strcmp (cmethod->name, "UnsafeLoad") == 0)
5876                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
5877                 else if (strcmp (cmethod->name, "UnsafeMov") == 0)
5878                         return emit_array_unsafe_mov (cfg, fsig, args);
5879         }
5880
5881         return NULL;
5882 }
5883
5884 static MonoInst*
5885 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5886 {
5887         MonoInst *ins = NULL;
5888
5889         static MonoClass *runtime_helpers_class = NULL;
5890         if (! runtime_helpers_class)
5891                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
5892                         "System.Runtime.CompilerServices", "RuntimeHelpers");
5893
5894         if (cmethod->klass == mono_defaults.string_class) {
5895                 if (strcmp (cmethod->name, "get_Chars") == 0 && fsig->param_count + fsig->hasthis == 2) {
5896                         int dreg = alloc_ireg (cfg);
5897                         int index_reg = alloc_preg (cfg);
5898                         int add_reg = alloc_preg (cfg);
5899
5900 #if SIZEOF_REGISTER == 8
5901                         if (COMPILE_LLVM (cfg)) {
5902                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, args [1]->dreg);
5903                         } else {
5904                                 /* The array reg is 64 bits but the index reg is only 32 */
5905                                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
5906                         }
5907 #else
5908                         index_reg = args [1]->dreg;
5909 #endif  
5910                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
5911
5912 #if defined(TARGET_X86) || defined(TARGET_AMD64)
5913                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, MONO_STRUCT_OFFSET (MonoString, chars));
5914                         add_reg = ins->dreg;
5915                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5916                                                                    add_reg, 0);
5917 #else
5918                         int mult_reg = alloc_preg (cfg);
5919                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5920                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5921                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5922                                                                    add_reg, MONO_STRUCT_OFFSET (MonoString, chars));
5923 #endif
5924                         type_from_op (cfg, ins, NULL, NULL);
5925                         return ins;
5926                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
5927                         int dreg = alloc_ireg (cfg);
5928                         /* Decompose later to allow more optimizations */
5929                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5930                         ins->type = STACK_I4;
5931                         ins->flags |= MONO_INST_FAULT;
5932                         cfg->cbb->has_array_access = TRUE;
5933                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5934
5935                         return ins;
5936                 } else 
5937                         return NULL;
5938         } else if (cmethod->klass == mono_defaults.object_class) {
5939
5940                 if (strcmp (cmethod->name, "GetType") == 0 && fsig->param_count + fsig->hasthis == 1) {
5941                         int dreg = alloc_ireg_ref (cfg);
5942                         int vt_reg = alloc_preg (cfg);
5943                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
5944                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, type));
5945                         type_from_op (cfg, ins, NULL, NULL);
5946
5947                         return ins;
5948                 } else if (!cfg->backend->emulate_mul_div && strcmp (cmethod->name, "InternalGetHashCode") == 0 && fsig->param_count == 1 && !mono_gc_is_moving ()) {
5949                         int dreg = alloc_ireg (cfg);
5950                         int t1 = alloc_ireg (cfg);
5951         
5952                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5953                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5954                         ins->type = STACK_I4;
5955
5956                         return ins;
5957                 } else if (strcmp (cmethod->name, ".ctor") == 0 && fsig->param_count == 0) {
5958                         MONO_INST_NEW (cfg, ins, OP_NOP);
5959                         MONO_ADD_INS (cfg->cbb, ins);
5960                         return ins;
5961                 } else
5962                         return NULL;
5963         } else if (cmethod->klass == mono_defaults.array_class) {
5964                 if (strcmp (cmethod->name, "GetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5965                         return emit_array_generic_access (cfg, fsig, args, FALSE);
5966                 else if (strcmp (cmethod->name, "SetGenericValueImpl") == 0 && fsig->param_count + fsig->hasthis == 3 && !cfg->gsharedvt)
5967                         return emit_array_generic_access (cfg, fsig, args, TRUE);
5968
5969 #ifndef MONO_BIG_ARRAYS
5970                 /*
5971                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5972                  * Array methods.
5973                  */
5974                 else if (((strcmp (cmethod->name, "GetLength") == 0 && fsig->param_count + fsig->hasthis == 2) ||
5975                          (strcmp (cmethod->name, "GetLowerBound") == 0 && fsig->param_count + fsig->hasthis == 2)) &&
5976                          args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5977                         int dreg = alloc_ireg (cfg);
5978                         int bounds_reg = alloc_ireg_mp (cfg);
5979                         MonoBasicBlock *end_bb, *szarray_bb;
5980                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5981
5982                         NEW_BBLOCK (cfg, end_bb);
5983                         NEW_BBLOCK (cfg, szarray_bb);
5984
5985                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5986                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, bounds));
5987                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5988                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5989                         /* Non-szarray case */
5990                         if (get_length)
5991                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5992                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, length));
5993                         else
5994                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5995                                                                            bounds_reg, MONO_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5996                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5997                         MONO_START_BB (cfg, szarray_bb);
5998                         /* Szarray case */
5999                         if (get_length)
6000                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
6001                                                                            args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6002                         else
6003                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6004                         MONO_START_BB (cfg, end_bb);
6005
6006                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
6007                         ins->type = STACK_I4;
6008                         
6009                         return ins;
6010                 }
6011 #endif
6012
6013                 if (cmethod->name [0] != 'g')
6014                         return NULL;
6015
6016                 if (strcmp (cmethod->name, "get_Rank") == 0 && fsig->param_count + fsig->hasthis == 1) {
6017                         int dreg = alloc_ireg (cfg);
6018                         int vtable_reg = alloc_preg (cfg);
6019                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
6020                                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
6021                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
6022                                                                    vtable_reg, MONO_STRUCT_OFFSET (MonoVTable, rank));
6023                         type_from_op (cfg, ins, NULL, NULL);
6024
6025                         return ins;
6026                 } else if (strcmp (cmethod->name, "get_Length") == 0 && fsig->param_count + fsig->hasthis == 1) {
6027                         int dreg = alloc_ireg (cfg);
6028
6029                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
6030                                                                                  args [0]->dreg, MONO_STRUCT_OFFSET (MonoArray, max_length));
6031                         type_from_op (cfg, ins, NULL, NULL);
6032
6033                         return ins;
6034                 } else
6035                         return NULL;
6036         } else if (cmethod->klass == runtime_helpers_class) {
6037
6038                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0 && fsig->param_count == 0) {
6039                         EMIT_NEW_ICONST (cfg, ins, MONO_STRUCT_OFFSET (MonoString, chars));
6040                         return ins;
6041                 } else
6042                         return NULL;
6043         } else if (cmethod->klass == mono_defaults.thread_class) {
6044                 if (strcmp (cmethod->name, "SpinWait_nop") == 0 && fsig->param_count == 0) {
6045                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
6046                         MONO_ADD_INS (cfg->cbb, ins);
6047                         return ins;
6048                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0) {
6049                         return emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6050                 } else if (!strcmp (cmethod->name, "VolatileRead") && fsig->param_count == 1) {
6051                         guint32 opcode = 0;
6052                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6053
6054                         if (fsig->params [0]->type == MONO_TYPE_I1)
6055                                 opcode = OP_LOADI1_MEMBASE;
6056                         else if (fsig->params [0]->type == MONO_TYPE_U1)
6057                                 opcode = OP_LOADU1_MEMBASE;
6058                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6059                                 opcode = OP_LOADI2_MEMBASE;
6060                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6061                                 opcode = OP_LOADU2_MEMBASE;
6062                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6063                                 opcode = OP_LOADI4_MEMBASE;
6064                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6065                                 opcode = OP_LOADU4_MEMBASE;
6066                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6067                                 opcode = OP_LOADI8_MEMBASE;
6068                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6069                                 opcode = OP_LOADR4_MEMBASE;
6070                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6071                                 opcode = OP_LOADR8_MEMBASE;
6072                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6073                                 opcode = OP_LOAD_MEMBASE;
6074
6075                         if (opcode) {
6076                                 MONO_INST_NEW (cfg, ins, opcode);
6077                                 ins->inst_basereg = args [0]->dreg;
6078                                 ins->inst_offset = 0;
6079                                 MONO_ADD_INS (cfg->cbb, ins);
6080
6081                                 switch (fsig->params [0]->type) {
6082                                 case MONO_TYPE_I1:
6083                                 case MONO_TYPE_U1:
6084                                 case MONO_TYPE_I2:
6085                                 case MONO_TYPE_U2:
6086                                 case MONO_TYPE_I4:
6087                                 case MONO_TYPE_U4:
6088                                         ins->dreg = mono_alloc_ireg (cfg);
6089                                         ins->type = STACK_I4;
6090                                         break;
6091                                 case MONO_TYPE_I8:
6092                                 case MONO_TYPE_U8:
6093                                         ins->dreg = mono_alloc_lreg (cfg);
6094                                         ins->type = STACK_I8;
6095                                         break;
6096                                 case MONO_TYPE_I:
6097                                 case MONO_TYPE_U:
6098                                         ins->dreg = mono_alloc_ireg (cfg);
6099 #if SIZEOF_REGISTER == 8
6100                                         ins->type = STACK_I8;
6101 #else
6102                                         ins->type = STACK_I4;
6103 #endif
6104                                         break;
6105                                 case MONO_TYPE_R4:
6106                                 case MONO_TYPE_R8:
6107                                         ins->dreg = mono_alloc_freg (cfg);
6108                                         ins->type = STACK_R8;
6109                                         break;
6110                                 default:
6111                                         g_assert (mini_type_is_reference (fsig->params [0]));
6112                                         ins->dreg = mono_alloc_ireg_ref (cfg);
6113                                         ins->type = STACK_OBJ;
6114                                         break;
6115                                 }
6116
6117                                 if (opcode == OP_LOADI8_MEMBASE)
6118                                         ins = mono_decompose_opcode (cfg, ins);
6119
6120                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
6121
6122                                 return ins;
6123                         }
6124                 } else if (!strcmp (cmethod->name, "VolatileWrite") && fsig->param_count == 2) {
6125                         guint32 opcode = 0;
6126                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6127
6128                         if (fsig->params [0]->type == MONO_TYPE_I1 || fsig->params [0]->type == MONO_TYPE_U1)
6129                                 opcode = OP_STOREI1_MEMBASE_REG;
6130                         else if (fsig->params [0]->type == MONO_TYPE_I2 || fsig->params [0]->type == MONO_TYPE_U2)
6131                                 opcode = OP_STOREI2_MEMBASE_REG;
6132                         else if (fsig->params [0]->type == MONO_TYPE_I4 || fsig->params [0]->type == MONO_TYPE_U4)
6133                                 opcode = OP_STOREI4_MEMBASE_REG;
6134                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_U8)
6135                                 opcode = OP_STOREI8_MEMBASE_REG;
6136                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6137                                 opcode = OP_STORER4_MEMBASE_REG;
6138                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6139                                 opcode = OP_STORER8_MEMBASE_REG;
6140                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I || fsig->params [0]->type == MONO_TYPE_U)
6141                                 opcode = OP_STORE_MEMBASE_REG;
6142
6143                         if (opcode) {
6144                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
6145
6146                                 MONO_INST_NEW (cfg, ins, opcode);
6147                                 ins->sreg1 = args [1]->dreg;
6148                                 ins->inst_destbasereg = args [0]->dreg;
6149                                 ins->inst_offset = 0;
6150                                 MONO_ADD_INS (cfg->cbb, ins);
6151
6152                                 if (opcode == OP_STOREI8_MEMBASE_REG)
6153                                         ins = mono_decompose_opcode (cfg, ins);
6154
6155                                 return ins;
6156                         }
6157                 }
6158         } else if (cmethod->klass->image == mono_defaults.corlib &&
6159                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6160                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
6161                 ins = NULL;
6162
6163 #if SIZEOF_REGISTER == 8
6164                 if (!cfg->llvm_only && strcmp (cmethod->name, "Read") == 0 && fsig->param_count == 1 && (fsig->params [0]->type == MONO_TYPE_I8)) {
6165                         if (!cfg->llvm_only && mono_arch_opcode_supported (OP_ATOMIC_LOAD_I8)) {
6166                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_LOAD_I8);
6167                                 ins->dreg = mono_alloc_preg (cfg);
6168                                 ins->sreg1 = args [0]->dreg;
6169                                 ins->type = STACK_I8;
6170                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_SEQ;
6171                                 MONO_ADD_INS (cfg->cbb, ins);
6172                         } else {
6173                                 MonoInst *load_ins;
6174
6175                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6176
6177                                 /* 64 bit reads are already atomic */
6178                                 MONO_INST_NEW (cfg, load_ins, OP_LOADI8_MEMBASE);
6179                                 load_ins->dreg = mono_alloc_preg (cfg);
6180                                 load_ins->inst_basereg = args [0]->dreg;
6181                                 load_ins->inst_offset = 0;
6182                                 load_ins->type = STACK_I8;
6183                                 MONO_ADD_INS (cfg->cbb, load_ins);
6184
6185                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6186
6187                                 ins = load_ins;
6188                         }
6189                 }
6190 #endif
6191
6192                 if (strcmp (cmethod->name, "Increment") == 0 && fsig->param_count == 1) {
6193                         MonoInst *ins_iconst;
6194                         guint32 opcode = 0;
6195
6196                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6197                                 opcode = OP_ATOMIC_ADD_I4;
6198                                 cfg->has_atomic_add_i4 = TRUE;
6199                         }
6200 #if SIZEOF_REGISTER == 8
6201                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6202                                 opcode = OP_ATOMIC_ADD_I8;
6203 #endif
6204                         if (opcode) {
6205                                 if (!mono_arch_opcode_supported (opcode))
6206                                         return NULL;
6207                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6208                                 ins_iconst->inst_c0 = 1;
6209                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6210                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6211
6212                                 MONO_INST_NEW (cfg, ins, opcode);
6213                                 ins->dreg = mono_alloc_ireg (cfg);
6214                                 ins->inst_basereg = args [0]->dreg;
6215                                 ins->inst_offset = 0;
6216                                 ins->sreg2 = ins_iconst->dreg;
6217                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6218                                 MONO_ADD_INS (cfg->cbb, ins);
6219                         }
6220                 } else if (strcmp (cmethod->name, "Decrement") == 0 && fsig->param_count == 1) {
6221                         MonoInst *ins_iconst;
6222                         guint32 opcode = 0;
6223
6224                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6225                                 opcode = OP_ATOMIC_ADD_I4;
6226                                 cfg->has_atomic_add_i4 = TRUE;
6227                         }
6228 #if SIZEOF_REGISTER == 8
6229                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6230                                 opcode = OP_ATOMIC_ADD_I8;
6231 #endif
6232                         if (opcode) {
6233                                 if (!mono_arch_opcode_supported (opcode))
6234                                         return NULL;
6235                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
6236                                 ins_iconst->inst_c0 = -1;
6237                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
6238                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
6239
6240                                 MONO_INST_NEW (cfg, ins, opcode);
6241                                 ins->dreg = mono_alloc_ireg (cfg);
6242                                 ins->inst_basereg = args [0]->dreg;
6243                                 ins->inst_offset = 0;
6244                                 ins->sreg2 = ins_iconst->dreg;
6245                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6246                                 MONO_ADD_INS (cfg->cbb, ins);
6247                         }
6248                 } else if (strcmp (cmethod->name, "Add") == 0 && fsig->param_count == 2) {
6249                         guint32 opcode = 0;
6250
6251                         if (fsig->params [0]->type == MONO_TYPE_I4) {
6252                                 opcode = OP_ATOMIC_ADD_I4;
6253                                 cfg->has_atomic_add_i4 = TRUE;
6254                         }
6255 #if SIZEOF_REGISTER == 8
6256                         else if (fsig->params [0]->type == MONO_TYPE_I8)
6257                                 opcode = OP_ATOMIC_ADD_I8;
6258 #endif
6259                         if (opcode) {
6260                                 if (!mono_arch_opcode_supported (opcode))
6261                                         return NULL;
6262                                 MONO_INST_NEW (cfg, ins, opcode);
6263                                 ins->dreg = mono_alloc_ireg (cfg);
6264                                 ins->inst_basereg = args [0]->dreg;
6265                                 ins->inst_offset = 0;
6266                                 ins->sreg2 = args [1]->dreg;
6267                                 ins->type = (opcode == OP_ATOMIC_ADD_I4) ? STACK_I4 : STACK_I8;
6268                                 MONO_ADD_INS (cfg->cbb, ins);
6269                         }
6270                 }
6271                 else if (strcmp (cmethod->name, "Exchange") == 0 && fsig->param_count == 2) {
6272                         MonoInst *f2i = NULL, *i2f;
6273                         guint32 opcode, f2i_opcode, i2f_opcode;
6274                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6275                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6276
6277                         if (fsig->params [0]->type == MONO_TYPE_I4 ||
6278                             fsig->params [0]->type == MONO_TYPE_R4) {
6279                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6280                                 f2i_opcode = OP_MOVE_F_TO_I4;
6281                                 i2f_opcode = OP_MOVE_I4_TO_F;
6282                                 cfg->has_atomic_exchange_i4 = TRUE;
6283                         }
6284 #if SIZEOF_REGISTER == 8
6285                         else if (is_ref ||
6286                                  fsig->params [0]->type == MONO_TYPE_I8 ||
6287                                  fsig->params [0]->type == MONO_TYPE_R8 ||
6288                                  fsig->params [0]->type == MONO_TYPE_I) {
6289                                 opcode = OP_ATOMIC_EXCHANGE_I8;
6290                                 f2i_opcode = OP_MOVE_F_TO_I8;
6291                                 i2f_opcode = OP_MOVE_I8_TO_F;
6292                         }
6293 #else
6294                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_I) {
6295                                 opcode = OP_ATOMIC_EXCHANGE_I4;
6296                                 cfg->has_atomic_exchange_i4 = TRUE;
6297                         }
6298 #endif
6299                         else
6300                                 return NULL;
6301
6302                         if (!mono_arch_opcode_supported (opcode))
6303                                 return NULL;
6304
6305                         if (is_float) {
6306                                 /* TODO: Decompose these opcodes instead of bailing here. */
6307                                 if (COMPILE_SOFT_FLOAT (cfg))
6308                                         return NULL;
6309
6310                                 MONO_INST_NEW (cfg, f2i, f2i_opcode);
6311                                 f2i->dreg = mono_alloc_ireg (cfg);
6312                                 f2i->sreg1 = args [1]->dreg;
6313                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6314                                         f2i->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6315                                 MONO_ADD_INS (cfg->cbb, f2i);
6316                         }
6317
6318                         MONO_INST_NEW (cfg, ins, opcode);
6319                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
6320                         ins->inst_basereg = args [0]->dreg;
6321                         ins->inst_offset = 0;
6322                         ins->sreg2 = is_float ? f2i->dreg : args [1]->dreg;
6323                         MONO_ADD_INS (cfg->cbb, ins);
6324
6325                         switch (fsig->params [0]->type) {
6326                         case MONO_TYPE_I4:
6327                                 ins->type = STACK_I4;
6328                                 break;
6329                         case MONO_TYPE_I8:
6330                                 ins->type = STACK_I8;
6331                                 break;
6332                         case MONO_TYPE_I:
6333 #if SIZEOF_REGISTER == 8
6334                                 ins->type = STACK_I8;
6335 #else
6336                                 ins->type = STACK_I4;
6337 #endif
6338                                 break;
6339                         case MONO_TYPE_R4:
6340                         case MONO_TYPE_R8:
6341                                 ins->type = STACK_R8;
6342                                 break;
6343                         default:
6344                                 g_assert (mini_type_is_reference (fsig->params [0]));
6345                                 ins->type = STACK_OBJ;
6346                                 break;
6347                         }
6348
6349                         if (is_float) {
6350                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6351                                 i2f->dreg = mono_alloc_freg (cfg);
6352                                 i2f->sreg1 = ins->dreg;
6353                                 i2f->type = STACK_R8;
6354                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6355                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6356                                 MONO_ADD_INS (cfg->cbb, i2f);
6357
6358                                 ins = i2f;
6359                         }
6360
6361                         if (cfg->gen_write_barriers && is_ref)
6362                                 emit_write_barrier (cfg, args [0], args [1]);
6363                 }
6364                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 3) {
6365                         MonoInst *f2i_new = NULL, *f2i_cmp = NULL, *i2f;
6366                         guint32 opcode, f2i_opcode, i2f_opcode;
6367                         gboolean is_ref = mini_type_is_reference (fsig->params [1]);
6368                         gboolean is_float = fsig->params [1]->type == MONO_TYPE_R4 || fsig->params [1]->type == MONO_TYPE_R8;
6369
6370                         if (fsig->params [1]->type == MONO_TYPE_I4 ||
6371                             fsig->params [1]->type == MONO_TYPE_R4) {
6372                                 opcode = OP_ATOMIC_CAS_I4;
6373                                 f2i_opcode = OP_MOVE_F_TO_I4;
6374                                 i2f_opcode = OP_MOVE_I4_TO_F;
6375                                 cfg->has_atomic_cas_i4 = TRUE;
6376                         }
6377 #if SIZEOF_REGISTER == 8
6378                         else if (is_ref ||
6379                                  fsig->params [1]->type == MONO_TYPE_I8 ||
6380                                  fsig->params [1]->type == MONO_TYPE_R8 ||
6381                                  fsig->params [1]->type == MONO_TYPE_I) {
6382                                 opcode = OP_ATOMIC_CAS_I8;
6383                                 f2i_opcode = OP_MOVE_F_TO_I8;
6384                                 i2f_opcode = OP_MOVE_I8_TO_F;
6385                         }
6386 #else
6387                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I) {
6388                                 opcode = OP_ATOMIC_CAS_I4;
6389                                 cfg->has_atomic_cas_i4 = TRUE;
6390                         }
6391 #endif
6392                         else
6393                                 return NULL;
6394
6395                         if (!mono_arch_opcode_supported (opcode))
6396                                 return NULL;
6397
6398                         if (is_float) {
6399                                 /* TODO: Decompose these opcodes instead of bailing here. */
6400                                 if (COMPILE_SOFT_FLOAT (cfg))
6401                                         return NULL;
6402
6403                                 MONO_INST_NEW (cfg, f2i_new, f2i_opcode);
6404                                 f2i_new->dreg = mono_alloc_ireg (cfg);
6405                                 f2i_new->sreg1 = args [1]->dreg;
6406                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6407                                         f2i_new->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6408                                 MONO_ADD_INS (cfg->cbb, f2i_new);
6409
6410                                 MONO_INST_NEW (cfg, f2i_cmp, f2i_opcode);
6411                                 f2i_cmp->dreg = mono_alloc_ireg (cfg);
6412                                 f2i_cmp->sreg1 = args [2]->dreg;
6413                                 if (f2i_opcode == OP_MOVE_F_TO_I4)
6414                                         f2i_cmp->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6415                                 MONO_ADD_INS (cfg->cbb, f2i_cmp);
6416                         }
6417
6418                         MONO_INST_NEW (cfg, ins, opcode);
6419                         ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
6420                         ins->sreg1 = args [0]->dreg;
6421                         ins->sreg2 = is_float ? f2i_new->dreg : args [1]->dreg;
6422                         ins->sreg3 = is_float ? f2i_cmp->dreg : args [2]->dreg;
6423                         MONO_ADD_INS (cfg->cbb, ins);
6424
6425                         switch (fsig->params [1]->type) {
6426                         case MONO_TYPE_I4:
6427                                 ins->type = STACK_I4;
6428                                 break;
6429                         case MONO_TYPE_I8:
6430                                 ins->type = STACK_I8;
6431                                 break;
6432                         case MONO_TYPE_I:
6433 #if SIZEOF_REGISTER == 8
6434                                 ins->type = STACK_I8;
6435 #else
6436                                 ins->type = STACK_I4;
6437 #endif
6438                                 break;
6439                         case MONO_TYPE_R4:
6440                                 ins->type = cfg->r4_stack_type;
6441                                 break;
6442                         case MONO_TYPE_R8:
6443                                 ins->type = STACK_R8;
6444                                 break;
6445                         default:
6446                                 g_assert (mini_type_is_reference (fsig->params [1]));
6447                                 ins->type = STACK_OBJ;
6448                                 break;
6449                         }
6450
6451                         if (is_float) {
6452                                 MONO_INST_NEW (cfg, i2f, i2f_opcode);
6453                                 i2f->dreg = mono_alloc_freg (cfg);
6454                                 i2f->sreg1 = ins->dreg;
6455                                 i2f->type = STACK_R8;
6456                                 if (i2f_opcode == OP_MOVE_I4_TO_F)
6457                                         i2f->backend.spill_var = mini_get_int_to_float_spill_area (cfg);
6458                                 MONO_ADD_INS (cfg->cbb, i2f);
6459
6460                                 ins = i2f;
6461                         }
6462
6463                         if (cfg->gen_write_barriers && is_ref)
6464                                 emit_write_barrier (cfg, args [0], args [1]);
6465                 }
6466                 else if ((strcmp (cmethod->name, "CompareExchange") == 0) && fsig->param_count == 4 &&
6467                          fsig->params [1]->type == MONO_TYPE_I4) {
6468                         MonoInst *cmp, *ceq;
6469
6470                         if (!mono_arch_opcode_supported (OP_ATOMIC_CAS_I4))
6471                                 return NULL;
6472
6473                         /* int32 r = CAS (location, value, comparand); */
6474                         MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
6475                         ins->dreg = alloc_ireg (cfg);
6476                         ins->sreg1 = args [0]->dreg;
6477                         ins->sreg2 = args [1]->dreg;
6478                         ins->sreg3 = args [2]->dreg;
6479                         ins->type = STACK_I4;
6480                         MONO_ADD_INS (cfg->cbb, ins);
6481
6482                         /* bool result = r == comparand; */
6483                         MONO_INST_NEW (cfg, cmp, OP_ICOMPARE);
6484                         cmp->sreg1 = ins->dreg;
6485                         cmp->sreg2 = args [2]->dreg;
6486                         cmp->type = STACK_I4;
6487                         MONO_ADD_INS (cfg->cbb, cmp);
6488
6489                         MONO_INST_NEW (cfg, ceq, OP_ICEQ);
6490                         ceq->dreg = alloc_ireg (cfg);
6491                         ceq->type = STACK_I4;
6492                         MONO_ADD_INS (cfg->cbb, ceq);
6493
6494                         /* *success = result; */
6495                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, args [3]->dreg, 0, ceq->dreg);
6496
6497                         cfg->has_atomic_cas_i4 = TRUE;
6498                 }
6499                 else if (strcmp (cmethod->name, "MemoryBarrier") == 0 && fsig->param_count == 0)
6500                         ins = emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
6501
6502                 if (ins)
6503                         return ins;
6504         } else if (cmethod->klass->image == mono_defaults.corlib &&
6505                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
6506                            (strcmp (cmethod->klass->name, "Volatile") == 0)) {
6507                 ins = NULL;
6508
6509                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Read") && fsig->param_count == 1) {
6510                         guint32 opcode = 0;
6511                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6512                         gboolean is_float = fsig->params [0]->type == MONO_TYPE_R4 || fsig->params [0]->type == MONO_TYPE_R8;
6513
6514                         if (fsig->params [0]->type == MONO_TYPE_I1)
6515                                 opcode = OP_ATOMIC_LOAD_I1;
6516                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6517                                 opcode = OP_ATOMIC_LOAD_U1;
6518                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6519                                 opcode = OP_ATOMIC_LOAD_I2;
6520                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6521                                 opcode = OP_ATOMIC_LOAD_U2;
6522                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6523                                 opcode = OP_ATOMIC_LOAD_I4;
6524                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6525                                 opcode = OP_ATOMIC_LOAD_U4;
6526                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6527                                 opcode = OP_ATOMIC_LOAD_R4;
6528                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6529                                 opcode = OP_ATOMIC_LOAD_R8;
6530 #if SIZEOF_REGISTER == 8
6531                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6532                                 opcode = OP_ATOMIC_LOAD_I8;
6533                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6534                                 opcode = OP_ATOMIC_LOAD_U8;
6535 #else
6536                         else if (fsig->params [0]->type == MONO_TYPE_I)
6537                                 opcode = OP_ATOMIC_LOAD_I4;
6538                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6539                                 opcode = OP_ATOMIC_LOAD_U4;
6540 #endif
6541
6542                         if (opcode) {
6543                                 if (!mono_arch_opcode_supported (opcode))
6544                                         return NULL;
6545
6546                                 MONO_INST_NEW (cfg, ins, opcode);
6547                                 ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : (is_float ? mono_alloc_freg (cfg) : mono_alloc_ireg (cfg));
6548                                 ins->sreg1 = args [0]->dreg;
6549                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_ACQ;
6550                                 MONO_ADD_INS (cfg->cbb, ins);
6551
6552                                 switch (fsig->params [0]->type) {
6553                                 case MONO_TYPE_BOOLEAN:
6554                                 case MONO_TYPE_I1:
6555                                 case MONO_TYPE_U1:
6556                                 case MONO_TYPE_I2:
6557                                 case MONO_TYPE_U2:
6558                                 case MONO_TYPE_I4:
6559                                 case MONO_TYPE_U4:
6560                                         ins->type = STACK_I4;
6561                                         break;
6562                                 case MONO_TYPE_I8:
6563                                 case MONO_TYPE_U8:
6564                                         ins->type = STACK_I8;
6565                                         break;
6566                                 case MONO_TYPE_I:
6567                                 case MONO_TYPE_U:
6568 #if SIZEOF_REGISTER == 8
6569                                         ins->type = STACK_I8;
6570 #else
6571                                         ins->type = STACK_I4;
6572 #endif
6573                                         break;
6574                                 case MONO_TYPE_R4:
6575                                         ins->type = cfg->r4_stack_type;
6576                                         break;
6577                                 case MONO_TYPE_R8:
6578                                         ins->type = STACK_R8;
6579                                         break;
6580                                 default:
6581                                         g_assert (mini_type_is_reference (fsig->params [0]));
6582                                         ins->type = STACK_OBJ;
6583                                         break;
6584                                 }
6585                         }
6586                 }
6587
6588                 if (!cfg->llvm_only && !strcmp (cmethod->name, "Write") && fsig->param_count == 2) {
6589                         guint32 opcode = 0;
6590                         gboolean is_ref = mini_type_is_reference (fsig->params [0]);
6591
6592                         if (fsig->params [0]->type == MONO_TYPE_I1)
6593                                 opcode = OP_ATOMIC_STORE_I1;
6594                         else if (fsig->params [0]->type == MONO_TYPE_U1 || fsig->params [0]->type == MONO_TYPE_BOOLEAN)
6595                                 opcode = OP_ATOMIC_STORE_U1;
6596                         else if (fsig->params [0]->type == MONO_TYPE_I2)
6597                                 opcode = OP_ATOMIC_STORE_I2;
6598                         else if (fsig->params [0]->type == MONO_TYPE_U2)
6599                                 opcode = OP_ATOMIC_STORE_U2;
6600                         else if (fsig->params [0]->type == MONO_TYPE_I4)
6601                                 opcode = OP_ATOMIC_STORE_I4;
6602                         else if (fsig->params [0]->type == MONO_TYPE_U4)
6603                                 opcode = OP_ATOMIC_STORE_U4;
6604                         else if (fsig->params [0]->type == MONO_TYPE_R4)
6605                                 opcode = OP_ATOMIC_STORE_R4;
6606                         else if (fsig->params [0]->type == MONO_TYPE_R8)
6607                                 opcode = OP_ATOMIC_STORE_R8;
6608 #if SIZEOF_REGISTER == 8
6609                         else if (fsig->params [0]->type == MONO_TYPE_I8 || fsig->params [0]->type == MONO_TYPE_I)
6610                                 opcode = OP_ATOMIC_STORE_I8;
6611                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U8 || fsig->params [0]->type == MONO_TYPE_U)
6612                                 opcode = OP_ATOMIC_STORE_U8;
6613 #else
6614                         else if (fsig->params [0]->type == MONO_TYPE_I)
6615                                 opcode = OP_ATOMIC_STORE_I4;
6616                         else if (is_ref || fsig->params [0]->type == MONO_TYPE_U)
6617                                 opcode = OP_ATOMIC_STORE_U4;
6618 #endif
6619
6620                         if (opcode) {
6621                                 if (!mono_arch_opcode_supported (opcode))
6622                                         return NULL;
6623
6624                                 MONO_INST_NEW (cfg, ins, opcode);
6625                                 ins->dreg = args [0]->dreg;
6626                                 ins->sreg1 = args [1]->dreg;
6627                                 ins->backend.memory_barrier_kind = MONO_MEMORY_BARRIER_REL;
6628                                 MONO_ADD_INS (cfg->cbb, ins);
6629
6630                                 if (cfg->gen_write_barriers && is_ref)
6631                                         emit_write_barrier (cfg, args [0], args [1]);
6632                         }
6633                 }
6634
6635                 if (ins)
6636                         return ins;
6637         } else if (cmethod->klass->image == mono_defaults.corlib &&
6638                            (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
6639                            (strcmp (cmethod->klass->name, "Debugger") == 0)) {
6640                 if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
6641                         if (should_insert_brekpoint (cfg->method)) {
6642                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
6643                         } else {
6644                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6645                                 MONO_ADD_INS (cfg->cbb, ins);
6646                         }
6647                         return ins;
6648                 }
6649         } else if (cmethod->klass->image == mono_defaults.corlib &&
6650                    (strcmp (cmethod->klass->name_space, "System") == 0) &&
6651                    (strcmp (cmethod->klass->name, "Environment") == 0)) {
6652                 if (!strcmp (cmethod->name, "get_IsRunningOnWindows") && fsig->param_count == 0) {
6653 #ifdef TARGET_WIN32
6654                         EMIT_NEW_ICONST (cfg, ins, 1);
6655 #else
6656                         EMIT_NEW_ICONST (cfg, ins, 0);
6657 #endif
6658                 }
6659         } else if (cmethod->klass->image == mono_defaults.corlib &&
6660                            (strcmp (cmethod->klass->name_space, "System.Reflection") == 0) &&
6661                            (strcmp (cmethod->klass->name, "Assembly") == 0)) {
6662                 if (cfg->llvm_only && !strcmp (cmethod->name, "GetExecutingAssembly")) {
6663                         /* No stack walks are current available, so implement this as an intrinsic */
6664                         MonoInst *assembly_ins;
6665
6666                         EMIT_NEW_AOTCONST (cfg, assembly_ins, MONO_PATCH_INFO_IMAGE, cfg->method->klass->image);
6667                         ins = mono_emit_jit_icall (cfg, mono_get_assembly_object, &assembly_ins);
6668                         return ins;
6669                 }
6670         } else if (cmethod->klass == mono_defaults.math_class) {
6671                 /* 
6672                  * There is general branchless code for Min/Max, but it does not work for 
6673                  * all inputs:
6674                  * http://everything2.com/?node_id=1051618
6675                  */
6676         } else if (((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") ||
6677                     !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) &&
6678                                 !strcmp (cmethod->klass->name_space, "XamCore.ObjCRuntime") &&
6679                                 !strcmp (cmethod->klass->name, "Selector")) ||
6680                            (!strcmp (cmethod->klass->image->assembly->aname.name, "Xamarin.iOS") &&
6681                                 !strcmp (cmethod->klass->name_space, "ObjCRuntime") &&
6682                                 !strcmp (cmethod->klass->name, "Selector"))
6683                            ) {
6684                 if (cfg->backend->have_objc_get_selector &&
6685                         !strcmp (cmethod->name, "GetHandle") && fsig->param_count == 1 &&
6686                     (args [0]->opcode == OP_GOT_ENTRY || args [0]->opcode == OP_AOTCONST) &&
6687                     cfg->compile_aot) {
6688                         MonoInst *pi;
6689                         MonoJumpInfoToken *ji;
6690                         MonoString *s;
6691
6692                         cfg->disable_llvm = TRUE;
6693
6694                         if (args [0]->opcode == OP_GOT_ENTRY) {
6695                                 pi = (MonoInst *)args [0]->inst_p1;
6696                                 g_assert (pi->opcode == OP_PATCH_INFO);
6697                                 g_assert (GPOINTER_TO_INT (pi->inst_p1) == MONO_PATCH_INFO_LDSTR);
6698                                 ji = (MonoJumpInfoToken *)pi->inst_p0;
6699                         } else {
6700                                 g_assert (GPOINTER_TO_INT (args [0]->inst_p1) == MONO_PATCH_INFO_LDSTR);
6701                                 ji = (MonoJumpInfoToken *)args [0]->inst_p0;
6702                         }
6703
6704                         NULLIFY_INS (args [0]);
6705
6706                         // FIXME: Ugly
6707                         s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
6708                         MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
6709                         ins->dreg = mono_alloc_ireg (cfg);
6710                         // FIXME: Leaks
6711                         ins->inst_p0 = mono_string_to_utf8 (s);
6712                         MONO_ADD_INS (cfg->cbb, ins);
6713                         return ins;
6714                 }
6715         }
6716
6717 #ifdef MONO_ARCH_SIMD_INTRINSICS
6718         if (cfg->opt & MONO_OPT_SIMD) {
6719                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
6720                 if (ins)
6721                         return ins;
6722         }
6723 #endif
6724
6725         ins = mono_emit_native_types_intrinsics (cfg, cmethod, fsig, args);
6726         if (ins)
6727                 return ins;
6728
6729         if (COMPILE_LLVM (cfg)) {
6730                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
6731                 if (ins)
6732                         return ins;
6733         }
6734
6735         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
6736 }
6737
6738 /*
6739  * This entry point could be used later for arbitrary method
6740  * redirection.
6741  */
6742 inline static MonoInst*
6743 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
6744                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this_ins)
6745 {
6746         if (method->klass == mono_defaults.string_class) {
6747                 /* managed string allocation support */
6748                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
6749                         MonoInst *iargs [2];
6750                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
6751                         MonoMethod *managed_alloc = NULL;
6752
6753                         g_assert (vtable); /*Should not fail since it System.String*/
6754 #ifndef MONO_CROSS_COMPILE
6755                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE, FALSE);
6756 #endif
6757                         if (!managed_alloc)
6758                                 return NULL;
6759                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
6760                         iargs [1] = args [0];
6761                         return mono_emit_method_call (cfg, managed_alloc, iargs, this_ins);
6762                 }
6763         }
6764         return NULL;
6765 }
6766
6767 static void
6768 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
6769 {
6770         MonoInst *store, *temp;
6771         int i;
6772
6773         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
6774                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
6775
6776                 /*
6777                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
6778                  * would be different than the MonoInst's used to represent arguments, and
6779                  * the ldelema implementation can't deal with that.
6780                  * Solution: When ldelema is used on an inline argument, create a var for 
6781                  * it, emit ldelema on that var, and emit the saving code below in
6782                  * inline_method () if needed.
6783                  */
6784                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
6785                 cfg->args [i] = temp;
6786                 /* This uses cfg->args [i] which is set by the preceeding line */
6787                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
6788                 store->cil_code = sp [0]->cil_code;
6789                 sp++;
6790         }
6791 }
6792
6793 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
6794 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
6795
6796 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6797 static gboolean
6798 check_inline_called_method_name_limit (MonoMethod *called_method)
6799 {
6800         int strncmp_result;
6801         static const char *limit = NULL;
6802         
6803         if (limit == NULL) {
6804                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
6805
6806                 if (limit_string != NULL)
6807                         limit = limit_string;
6808                 else
6809                         limit = "";
6810         }
6811
6812         if (limit [0] != '\0') {
6813                 char *called_method_name = mono_method_full_name (called_method, TRUE);
6814
6815                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
6816                 g_free (called_method_name);
6817         
6818                 //return (strncmp_result <= 0);
6819                 return (strncmp_result == 0);
6820         } else {
6821                 return TRUE;
6822         }
6823 }
6824 #endif
6825
6826 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6827 static gboolean
6828 check_inline_caller_method_name_limit (MonoMethod *caller_method)
6829 {
6830         int strncmp_result;
6831         static const char *limit = NULL;
6832         
6833         if (limit == NULL) {
6834                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
6835                 if (limit_string != NULL) {
6836                         limit = limit_string;
6837                 } else {
6838                         limit = "";
6839                 }
6840         }
6841
6842         if (limit [0] != '\0') {
6843                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
6844
6845                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
6846                 g_free (caller_method_name);
6847         
6848                 //return (strncmp_result <= 0);
6849                 return (strncmp_result == 0);
6850         } else {
6851                 return TRUE;
6852         }
6853 }
6854 #endif
6855
6856 static void
6857 emit_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6858 {
6859         static double r8_0 = 0.0;
6860         static float r4_0 = 0.0;
6861         MonoInst *ins;
6862         int t;
6863
6864         rtype = mini_get_underlying_type (rtype);
6865         t = rtype->type;
6866
6867         if (rtype->byref) {
6868                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6869         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6870                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
6871         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6872                 MONO_EMIT_NEW_I8CONST (cfg, dreg, 0);
6873         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6874                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6875                 ins->type = STACK_R4;
6876                 ins->inst_p0 = (void*)&r4_0;
6877                 ins->dreg = dreg;
6878                 MONO_ADD_INS (cfg->cbb, ins);
6879         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6880                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6881                 ins->type = STACK_R8;
6882                 ins->inst_p0 = (void*)&r8_0;
6883                 ins->dreg = dreg;
6884                 MONO_ADD_INS (cfg->cbb, ins);
6885         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6886                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6887                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6888         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6889                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (rtype));
6890         } else {
6891                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
6892         }
6893 }
6894
6895 static void
6896 emit_dummy_init_rvar (MonoCompile *cfg, int dreg, MonoType *rtype)
6897 {
6898         int t;
6899
6900         rtype = mini_get_underlying_type (rtype);
6901         t = rtype->type;
6902
6903         if (rtype->byref) {
6904                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_PCONST);
6905         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
6906                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_ICONST);
6907         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
6908                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_I8CONST);
6909         } else if (cfg->r4fp && t == MONO_TYPE_R4) {
6910                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R4CONST);
6911         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
6912                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_R8CONST);
6913         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
6914                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (rtype))) {
6915                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6916         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (rtype)) {
6917                 MONO_EMIT_NEW_DUMMY_INIT (cfg, dreg, OP_DUMMY_VZERO);
6918         } else {
6919                 emit_init_rvar (cfg, dreg, rtype);
6920         }
6921 }
6922
6923 /* If INIT is FALSE, emit dummy initialization statements to keep the IR valid */
6924 static void
6925 emit_init_local (MonoCompile *cfg, int local, MonoType *type, gboolean init)
6926 {
6927         MonoInst *var = cfg->locals [local];
6928         if (COMPILE_SOFT_FLOAT (cfg)) {
6929                 MonoInst *store;
6930                 int reg = alloc_dreg (cfg, (MonoStackType)var->type);
6931                 emit_init_rvar (cfg, reg, type);
6932                 EMIT_NEW_LOCSTORE (cfg, store, local, cfg->cbb->last_ins);
6933         } else {
6934                 if (init)
6935                         emit_init_rvar (cfg, var->dreg, type);
6936                 else
6937                         emit_dummy_init_rvar (cfg, var->dreg, type);
6938         }
6939 }
6940
6941 /*
6942  * inline_method:
6943  *
6944  *   Return the cost of inlining CMETHOD.
6945  */
6946 static int
6947 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
6948                            guchar *ip, guint real_offset, gboolean inline_always)
6949 {
6950         MonoInst *ins, *rvar = NULL;
6951         MonoMethodHeader *cheader;
6952         MonoBasicBlock *ebblock, *sbblock;
6953         int i, costs;
6954         MonoMethod *prev_inlined_method;
6955         MonoInst **prev_locals, **prev_args;
6956         MonoType **prev_arg_types;
6957         guint prev_real_offset;
6958         GHashTable *prev_cbb_hash;
6959         MonoBasicBlock **prev_cil_offset_to_bb;
6960         MonoBasicBlock *prev_cbb;
6961         unsigned char* prev_cil_start;
6962         guint32 prev_cil_offset_to_bb_len;
6963         MonoMethod *prev_current_method;
6964         MonoGenericContext *prev_generic_context;
6965         gboolean ret_var_set, prev_ret_var_set, prev_disable_inline, virtual_ = FALSE;
6966
6967         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
6968
6969 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
6970         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
6971                 return 0;
6972 #endif
6973 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
6974         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
6975                 return 0;
6976 #endif
6977
6978         if (!fsig)
6979                 fsig = mono_method_signature (cmethod);
6980
6981         if (cfg->verbose_level > 2)
6982                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
6983
6984         if (!cmethod->inline_info) {
6985                 cfg->stat_inlineable_methods++;
6986                 cmethod->inline_info = 1;
6987         }
6988
6989         /* allocate local variables */
6990         cheader = mono_method_get_header (cmethod);
6991
6992         if (cheader == NULL || mono_loader_get_last_error ()) {
6993                 MonoLoaderError *error = mono_loader_get_last_error ();
6994
6995                 if (cheader)
6996                         mono_metadata_free_mh (cheader);
6997                 if (inline_always && error)
6998                         mono_cfg_set_exception (cfg, error->exception_type);
6999
7000                 mono_loader_clear_error ();
7001                 return 0;
7002         }
7003
7004         /*Must verify before creating locals as it can cause the JIT to assert.*/
7005         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
7006                 mono_metadata_free_mh (cheader);
7007                 return 0;
7008         }
7009
7010         /* allocate space to store the return value */
7011         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7012                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
7013         }
7014
7015         prev_locals = cfg->locals;
7016         cfg->locals = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));
7017         for (i = 0; i < cheader->num_locals; ++i)
7018                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
7019
7020         /* allocate start and end blocks */
7021         /* This is needed so if the inline is aborted, we can clean up */
7022         NEW_BBLOCK (cfg, sbblock);
7023         sbblock->real_offset = real_offset;
7024
7025         NEW_BBLOCK (cfg, ebblock);
7026         ebblock->block_num = cfg->num_bblocks++;
7027         ebblock->real_offset = real_offset;
7028
7029         prev_args = cfg->args;
7030         prev_arg_types = cfg->arg_types;
7031         prev_inlined_method = cfg->inlined_method;
7032         cfg->inlined_method = cmethod;
7033         cfg->ret_var_set = FALSE;
7034         cfg->inline_depth ++;
7035         prev_real_offset = cfg->real_offset;
7036         prev_cbb_hash = cfg->cbb_hash;
7037         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
7038         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
7039         prev_cil_start = cfg->cil_start;
7040         prev_cbb = cfg->cbb;
7041         prev_current_method = cfg->current_method;
7042         prev_generic_context = cfg->generic_context;
7043         prev_ret_var_set = cfg->ret_var_set;
7044         prev_disable_inline = cfg->disable_inline;
7045
7046         if (ip && *ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
7047                 virtual_ = TRUE;
7048
7049         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, sp, real_offset, virtual_);
7050
7051         ret_var_set = cfg->ret_var_set;
7052
7053         cfg->inlined_method = prev_inlined_method;
7054         cfg->real_offset = prev_real_offset;
7055         cfg->cbb_hash = prev_cbb_hash;
7056         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
7057         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
7058         cfg->cil_start = prev_cil_start;
7059         cfg->locals = prev_locals;
7060         cfg->args = prev_args;
7061         cfg->arg_types = prev_arg_types;
7062         cfg->current_method = prev_current_method;
7063         cfg->generic_context = prev_generic_context;
7064         cfg->ret_var_set = prev_ret_var_set;
7065         cfg->disable_inline = prev_disable_inline;
7066         cfg->inline_depth --;
7067
7068         if ((costs >= 0 && costs < 60) || inline_always || (costs >= 0 && (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))) {
7069                 if (cfg->verbose_level > 2)
7070                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
7071                 
7072                 cfg->stat_inlined_methods++;
7073
7074                 /* always add some code to avoid block split failures */
7075                 MONO_INST_NEW (cfg, ins, OP_NOP);
7076                 MONO_ADD_INS (prev_cbb, ins);
7077
7078                 prev_cbb->next_bb = sbblock;
7079                 link_bblock (cfg, prev_cbb, sbblock);
7080
7081                 /* 
7082                  * Get rid of the begin and end bblocks if possible to aid local
7083                  * optimizations.
7084                  */
7085                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
7086
7087                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
7088                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
7089
7090                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
7091                         MonoBasicBlock *prev = ebblock->in_bb [0];
7092                         mono_merge_basic_blocks (cfg, prev, ebblock);
7093                         cfg->cbb = prev;
7094                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
7095                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
7096                                 cfg->cbb = prev_cbb;
7097                         }
7098                 } else {
7099                         /* 
7100                          * Its possible that the rvar is set in some prev bblock, but not in others.
7101                          * (#1835).
7102                          */
7103                         if (rvar) {
7104                                 MonoBasicBlock *bb;
7105
7106                                 for (i = 0; i < ebblock->in_count; ++i) {
7107                                         bb = ebblock->in_bb [i];
7108
7109                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
7110                                                 cfg->cbb = bb;
7111
7112                                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7113                                         }
7114                                 }
7115                         }
7116
7117                         cfg->cbb = ebblock;
7118                 }
7119
7120                 if (rvar) {
7121                         /*
7122                          * If the inlined method contains only a throw, then the ret var is not 
7123                          * set, so set it to a dummy value.
7124                          */
7125                         if (!ret_var_set)
7126                                 emit_init_rvar (cfg, rvar->dreg, fsig->ret);
7127
7128                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
7129                         *sp++ = ins;
7130                 }
7131                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7132                 return costs + 1;
7133         } else {
7134                 if (cfg->verbose_level > 2)
7135                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
7136                 cfg->exception_type = MONO_EXCEPTION_NONE;
7137                 mono_loader_clear_error ();
7138
7139                 /* This gets rid of the newly added bblocks */
7140                 cfg->cbb = prev_cbb;
7141         }
7142         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
7143         return 0;
7144 }
7145
7146 /*
7147  * Some of these comments may well be out-of-date.
7148  * Design decisions: we do a single pass over the IL code (and we do bblock 
7149  * splitting/merging in the few cases when it's required: a back jump to an IL
7150  * address that was not already seen as bblock starting point).
7151  * Code is validated as we go (full verification is still better left to metadata/verify.c).
7152  * Complex operations are decomposed in simpler ones right away. We need to let the 
7153  * arch-specific code peek and poke inside this process somehow (except when the 
7154  * optimizations can take advantage of the full semantic info of coarse opcodes).
7155  * All the opcodes of the form opcode.s are 'normalized' to opcode.
7156  * MonoInst->opcode initially is the IL opcode or some simplification of that 
7157  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
7158  * opcode with value bigger than OP_LAST.
7159  * At this point the IR can be handed over to an interpreter, a dumb code generator
7160  * or to the optimizing code generator that will translate it to SSA form.
7161  *
7162  * Profiling directed optimizations.
7163  * We may compile by default with few or no optimizations and instrument the code
7164  * or the user may indicate what methods to optimize the most either in a config file
7165  * or through repeated runs where the compiler applies offline the optimizations to 
7166  * each method and then decides if it was worth it.
7167  */
7168
7169 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
7170 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
7171 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
7172 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
7173 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
7174 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
7175 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
7176 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) TYPE_LOAD_ERROR ((klass))
7177
7178 /* offset from br.s -> br like opcodes */
7179 #define BIG_BRANCH_OFFSET 13
7180
7181 static gboolean
7182 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
7183 {
7184         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
7185
7186         return b == NULL || b == bb;
7187 }
7188
7189 static int
7190 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
7191 {
7192         unsigned char *ip = start;
7193         unsigned char *target;
7194         int i;
7195         guint cli_addr;
7196         MonoBasicBlock *bblock;
7197         const MonoOpcode *opcode;
7198
7199         while (ip < end) {
7200                 cli_addr = ip - start;
7201                 i = mono_opcode_value ((const guint8 **)&ip, end);
7202                 if (i < 0)
7203                         UNVERIFIED;
7204                 opcode = &mono_opcodes [i];
7205                 switch (opcode->argument) {
7206                 case MonoInlineNone:
7207                         ip++; 
7208                         break;
7209                 case MonoInlineString:
7210                 case MonoInlineType:
7211                 case MonoInlineField:
7212                 case MonoInlineMethod:
7213                 case MonoInlineTok:
7214                 case MonoInlineSig:
7215                 case MonoShortInlineR:
7216                 case MonoInlineI:
7217                         ip += 5;
7218                         break;
7219                 case MonoInlineVar:
7220                         ip += 3;
7221                         break;
7222                 case MonoShortInlineVar:
7223                 case MonoShortInlineI:
7224                         ip += 2;
7225                         break;
7226                 case MonoShortInlineBrTarget:
7227                         target = start + cli_addr + 2 + (signed char)ip [1];
7228                         GET_BBLOCK (cfg, bblock, target);
7229                         ip += 2;
7230                         if (ip < end)
7231                                 GET_BBLOCK (cfg, bblock, ip);
7232                         break;
7233                 case MonoInlineBrTarget:
7234                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
7235                         GET_BBLOCK (cfg, bblock, target);
7236                         ip += 5;
7237                         if (ip < end)
7238                                 GET_BBLOCK (cfg, bblock, ip);
7239                         break;
7240                 case MonoInlineSwitch: {
7241                         guint32 n = read32 (ip + 1);
7242                         guint32 j;
7243                         ip += 5;
7244                         cli_addr += 5 + 4 * n;
7245                         target = start + cli_addr;
7246                         GET_BBLOCK (cfg, bblock, target);
7247                         
7248                         for (j = 0; j < n; ++j) {
7249                                 target = start + cli_addr + (gint32)read32 (ip);
7250                                 GET_BBLOCK (cfg, bblock, target);
7251                                 ip += 4;
7252                         }
7253                         break;
7254                 }
7255                 case MonoInlineR:
7256                 case MonoInlineI8:
7257                         ip += 9;
7258                         break;
7259                 default:
7260                         g_assert_not_reached ();
7261                 }
7262
7263                 if (i == CEE_THROW) {
7264                         unsigned char *bb_start = ip - 1;
7265                         
7266                         /* Find the start of the bblock containing the throw */
7267                         bblock = NULL;
7268                         while ((bb_start >= start) && !bblock) {
7269                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
7270                                 bb_start --;
7271                         }
7272                         if (bblock)
7273                                 bblock->out_of_line = 1;
7274                 }
7275         }
7276         return 0;
7277 unverified:
7278 exception_exit:
7279         *pos = ip;
7280         return 1;
7281 }
7282
7283 static inline MonoMethod *
7284 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7285 {
7286         MonoMethod *method;
7287
7288         if (m->wrapper_type != MONO_WRAPPER_NONE) {
7289                 method = (MonoMethod *)mono_method_get_wrapper_data (m, token);
7290                 if (context) {
7291                         MonoError error;
7292                         method = mono_class_inflate_generic_method_checked (method, context, &error);
7293                         g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
7294                 }
7295         } else {
7296                 method = mono_get_method_full (m->klass->image, token, klass, context);
7297         }
7298
7299         return method;
7300 }
7301
7302 static inline MonoMethod *
7303 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
7304 {
7305         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
7306
7307         if (method && cfg && !cfg->gshared && mono_class_is_open_constructed_type (&method->klass->byval_arg))
7308                 return NULL;
7309
7310         return method;
7311 }
7312
7313 static inline MonoClass*
7314 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
7315 {
7316         MonoError error;
7317         MonoClass *klass;
7318
7319         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7320                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
7321                 if (context)
7322                         klass = mono_class_inflate_generic_class (klass, context);
7323         } else {
7324                 klass = mono_class_get_and_inflate_typespec_checked (method->klass->image, token, context, &error);
7325                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
7326         }
7327         if (klass)
7328                 mono_class_init (klass);
7329         return klass;
7330 }
7331
7332 static inline MonoMethodSignature*
7333 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
7334 {
7335         MonoMethodSignature *fsig;
7336
7337         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7338                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
7339         } else {
7340                 fsig = mono_metadata_parse_signature (method->klass->image, token);
7341         }
7342         if (context) {
7343                 MonoError error;
7344                 fsig = mono_inflate_generic_signature(fsig, context, &error);
7345                 // FIXME:
7346                 g_assert(mono_error_ok(&error));
7347         }
7348         return fsig;
7349 }
7350
7351 static MonoMethod*
7352 throw_exception (void)
7353 {
7354         static MonoMethod *method = NULL;
7355
7356         if (!method) {
7357                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
7358                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
7359         }
7360         g_assert (method);
7361         return method;
7362 }
7363
7364 static void
7365 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
7366 {
7367         MonoMethod *thrower = throw_exception ();
7368         MonoInst *args [1];
7369
7370         EMIT_NEW_PCONST (cfg, args [0], ex);
7371         mono_emit_method_call (cfg, thrower, args, NULL);
7372 }
7373
7374 /*
7375  * Return the original method is a wrapper is specified. We can only access 
7376  * the custom attributes from the original method.
7377  */
7378 static MonoMethod*
7379 get_original_method (MonoMethod *method)
7380 {
7381         if (method->wrapper_type == MONO_WRAPPER_NONE)
7382                 return method;
7383
7384         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
7385         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
7386                 return NULL;
7387
7388         /* in other cases we need to find the original method */
7389         return mono_marshal_method_from_wrapper (method);
7390 }
7391
7392 static void
7393 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field)
7394 {
7395         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7396         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
7397         if (ex)
7398                 emit_throw_exception (cfg, ex);
7399 }
7400
7401 static void
7402 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
7403 {
7404         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
7405         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
7406         if (ex)
7407                 emit_throw_exception (cfg, ex);
7408 }
7409
7410 /*
7411  * Check that the IL instructions at ip are the array initialization
7412  * sequence and return the pointer to the data and the size.
7413  */
7414 static const char*
7415 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
7416 {
7417         /*
7418          * newarr[System.Int32]
7419          * dup
7420          * ldtoken field valuetype ...
7421          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
7422          */
7423         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
7424                 MonoError error;
7425                 guint32 token = read32 (ip + 7);
7426                 guint32 field_token = read32 (ip + 2);
7427                 guint32 field_index = field_token & 0xffffff;
7428                 guint32 rva;
7429                 const char *data_ptr;
7430                 int size = 0;
7431                 MonoMethod *cmethod;
7432                 MonoClass *dummy_class;
7433                 MonoClassField *field = mono_field_from_token_checked (method->klass->image, field_token, &dummy_class, NULL, &error);
7434                 int dummy_align;
7435
7436                 if (!field) {
7437                         mono_error_cleanup (&error); /* FIXME don't swallow the error */
7438                         return NULL;
7439                 }
7440
7441                 *out_field_token = field_token;
7442
7443                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
7444                 if (!cmethod)
7445                         return NULL;
7446                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
7447                         return NULL;
7448                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
7449                 case MONO_TYPE_BOOLEAN:
7450                 case MONO_TYPE_I1:
7451                 case MONO_TYPE_U1:
7452                         size = 1; break;
7453                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
7454 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
7455                 case MONO_TYPE_CHAR:
7456                 case MONO_TYPE_I2:
7457                 case MONO_TYPE_U2:
7458                         size = 2; break;
7459                 case MONO_TYPE_I4:
7460                 case MONO_TYPE_U4:
7461                 case MONO_TYPE_R4:
7462                         size = 4; break;
7463                 case MONO_TYPE_R8:
7464                 case MONO_TYPE_I8:
7465                 case MONO_TYPE_U8:
7466                         size = 8; break;
7467 #endif
7468                 default:
7469                         return NULL;
7470                 }
7471                 size *= len;
7472                 if (size > mono_type_size (field->type, &dummy_align))
7473                     return NULL;
7474                 *out_size = size;
7475                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
7476                 if (!image_is_dynamic (method->klass->image)) {
7477                         field_index = read32 (ip + 2) & 0xffffff;
7478                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
7479                         data_ptr = mono_image_rva_map (method->klass->image, rva);
7480                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
7481                         /* for aot code we do the lookup on load */
7482                         if (aot && data_ptr)
7483                                 return (const char *)GUINT_TO_POINTER (rva);
7484                 } else {
7485                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
7486                         g_assert (!aot);
7487                         data_ptr = mono_field_get_data (field);
7488                 }
7489                 return data_ptr;
7490         }
7491         return NULL;
7492 }
7493
7494 static void
7495 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
7496 {
7497         char *method_fname = mono_method_full_name (method, TRUE);
7498         char *method_code;
7499         MonoMethodHeader *header = mono_method_get_header (method);
7500
7501         if (header->code_size == 0)
7502                 method_code = g_strdup ("method body is empty.");
7503         else
7504                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
7505         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7506         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
7507         g_free (method_fname);
7508         g_free (method_code);
7509         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
7510 }
7511
7512 static void
7513 set_exception_object (MonoCompile *cfg, MonoException *exception)
7514 {
7515         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
7516         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr, MONO_ROOT_SOURCE_JIT, "jit exception");
7517         cfg->exception_ptr = exception;
7518 }
7519
7520 static void
7521 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
7522 {
7523         MonoInst *ins;
7524         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
7525         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
7526                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
7527                 /* Optimize reg-reg moves away */
7528                 /* 
7529                  * Can't optimize other opcodes, since sp[0] might point to
7530                  * the last ins of a decomposed opcode.
7531                  */
7532                 sp [0]->dreg = (cfg)->locals [n]->dreg;
7533         } else {
7534                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
7535         }
7536 }
7537
7538 /*
7539  * ldloca inhibits many optimizations so try to get rid of it in common
7540  * cases.
7541  */
7542 static inline unsigned char *
7543 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
7544 {
7545         int local, token;
7546         MonoClass *klass;
7547         MonoType *type;
7548
7549         if (size == 1) {
7550                 local = ip [1];
7551                 ip += 2;
7552         } else {
7553                 local = read16 (ip + 2);
7554                 ip += 4;
7555         }
7556         
7557         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
7558                 /* From the INITOBJ case */
7559                 token = read32 (ip + 2);
7560                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
7561                 CHECK_TYPELOAD (klass);
7562                 type = mini_get_underlying_type (&klass->byval_arg);
7563                 emit_init_local (cfg, local, type, TRUE);
7564                 return ip + 6;
7565         }
7566  exception_exit:
7567         return NULL;
7568 }
7569
7570 static gboolean
7571 is_exception_class (MonoClass *klass)
7572 {
7573         while (klass) {
7574                 if (klass == mono_defaults.exception_class)
7575                         return TRUE;
7576                 klass = klass->parent;
7577         }
7578         return FALSE;
7579 }
7580
7581 /*
7582  * is_jit_optimizer_disabled:
7583  *
7584  *   Determine whenever M's assembly has a DebuggableAttribute with the
7585  * IsJITOptimizerDisabled flag set.
7586  */
7587 static gboolean
7588 is_jit_optimizer_disabled (MonoMethod *m)
7589 {
7590         MonoAssembly *ass = m->klass->image->assembly;
7591         MonoCustomAttrInfo* attrs;
7592         static MonoClass *klass;
7593         int i;
7594         gboolean val = FALSE;
7595
7596         g_assert (ass);
7597         if (ass->jit_optimizer_disabled_inited)
7598                 return ass->jit_optimizer_disabled;
7599
7600         if (!klass)
7601                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
7602         if (!klass) {
7603                 /* Linked away */
7604                 ass->jit_optimizer_disabled = FALSE;
7605                 mono_memory_barrier ();
7606                 ass->jit_optimizer_disabled_inited = TRUE;
7607                 return FALSE;
7608         }
7609
7610         attrs = mono_custom_attrs_from_assembly (ass);
7611         if (attrs) {
7612                 for (i = 0; i < attrs->num_attrs; ++i) {
7613                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
7614                         const gchar *p;
7615                         MonoMethodSignature *sig;
7616
7617                         if (!attr->ctor || attr->ctor->klass != klass)
7618                                 continue;
7619                         /* Decode the attribute. See reflection.c */
7620                         p = (const char*)attr->data;
7621                         g_assert (read16 (p) == 0x0001);
7622                         p += 2;
7623
7624                         // FIXME: Support named parameters
7625                         sig = mono_method_signature (attr->ctor);
7626                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
7627                                 continue;
7628                         /* Two boolean arguments */
7629                         p ++;
7630                         val = *p;
7631                 }
7632                 mono_custom_attrs_free (attrs);
7633         }
7634
7635         ass->jit_optimizer_disabled = val;
7636         mono_memory_barrier ();
7637         ass->jit_optimizer_disabled_inited = TRUE;
7638
7639         return val;
7640 }
7641
7642 static gboolean
7643 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig, int call_opcode)
7644 {
7645         gboolean supported_tail_call;
7646         int i;
7647
7648         supported_tail_call = mono_arch_tail_call_supported (cfg, mono_method_signature (method), mono_method_signature (cmethod));
7649
7650         for (i = 0; i < fsig->param_count; ++i) {
7651                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
7652                         /* These can point to the current method's stack */
7653                         supported_tail_call = FALSE;
7654         }
7655         if (fsig->hasthis && cmethod->klass->valuetype)
7656                 /* this might point to the current method's stack */
7657                 supported_tail_call = FALSE;
7658         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
7659                 supported_tail_call = FALSE;
7660         if (cfg->method->save_lmf)
7661                 supported_tail_call = FALSE;
7662         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
7663                 supported_tail_call = FALSE;
7664         if (call_opcode != CEE_CALL)
7665                 supported_tail_call = FALSE;
7666
7667         /* Debugging support */
7668 #if 0
7669         if (supported_tail_call) {
7670                 if (!mono_debug_count ())
7671                         supported_tail_call = FALSE;
7672         }
7673 #endif
7674
7675         return supported_tail_call;
7676 }
7677
7678 /*
7679  * handle_ctor_call:
7680  *
7681  *   Handle calls made to ctors from NEWOBJ opcodes.
7682  */
7683 static void
7684 handle_ctor_call (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, int context_used,
7685                                   MonoInst **sp, guint8 *ip, int *inline_costs)
7686 {
7687         MonoInst *vtable_arg = NULL, *callvirt_this_arg = NULL, *ins;
7688
7689         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7690                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
7691                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7692                         mono_class_vtable (cfg->domain, cmethod->klass);
7693                         CHECK_TYPELOAD (cmethod->klass);
7694
7695                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7696                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7697                 } else {
7698                         if (context_used) {
7699                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7700                                                                                                    cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7701                         } else {
7702                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7703
7704                                 CHECK_TYPELOAD (cmethod->klass);
7705                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7706                         }
7707                 }
7708         }
7709
7710         /* Avoid virtual calls to ctors if possible */
7711         if (mono_class_is_marshalbyref (cmethod->klass))
7712                 callvirt_this_arg = sp [0];
7713
7714         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7715                 g_assert (MONO_TYPE_IS_VOID (fsig->ret));
7716                 CHECK_CFG_EXCEPTION;
7717         } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7718                            mono_method_check_inlining (cfg, cmethod) &&
7719                            !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE)) {
7720                 int costs;
7721
7722                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, FALSE))) {
7723                         cfg->real_offset += 5;
7724
7725                         *inline_costs += costs - 5;
7726                 } else {
7727                         INLINE_FAILURE ("inline failure");
7728                         // FIXME-VT: Clean this up
7729                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
7730                                 GSHAREDVT_FAILURE(*ip);
7731                         mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
7732                 }
7733         } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
7734                 MonoInst *addr;
7735
7736                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
7737                 mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
7738         } else if (context_used &&
7739                            ((!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
7740                                  !mono_class_generic_sharing_enabled (cmethod->klass)) || cfg->gsharedvt)) {
7741                 MonoInst *cmethod_addr;
7742
7743                 /* Generic calls made out of gsharedvt methods cannot be patched, so use an indirect call */
7744
7745                 cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7746                                                                                           cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7747
7748                 mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
7749         } else {
7750                 INLINE_FAILURE ("ctor call");
7751                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
7752                                                                                   callvirt_this_arg, NULL, vtable_arg);
7753         }
7754  exception_exit:
7755         return;
7756 }
7757
7758 static void
7759 emit_setret (MonoCompile *cfg, MonoInst *val)
7760 {
7761         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (cfg->method)->ret);
7762         MonoInst *ins;
7763
7764         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7765                 MonoInst *ret_addr;
7766
7767                 if (!cfg->vret_addr) {
7768                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, val);
7769                 } else {
7770                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7771
7772                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, val->dreg);
7773                         ins->klass = mono_class_from_mono_type (ret_type);
7774                 }
7775         } else {
7776 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
7777                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7778                         MonoInst *iargs [1];
7779                         MonoInst *conv;
7780
7781                         iargs [0] = val;
7782                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7783                         mono_arch_emit_setret (cfg, cfg->method, conv);
7784                 } else {
7785                         mono_arch_emit_setret (cfg, cfg->method, val);
7786                 }
7787 #else
7788                 mono_arch_emit_setret (cfg, cfg->method, val);
7789 #endif
7790         }
7791 }
7792
7793 static MonoMethodSignature*
7794 sig_to_rgctx_sig (MonoMethodSignature *sig)
7795 {
7796         // FIXME: memory allocation
7797         MonoMethodSignature *res;
7798         int i;
7799
7800         res = (MonoMethodSignature *)g_malloc (MONO_SIZEOF_METHOD_SIGNATURE + (sig->param_count + 1) * sizeof (MonoType*));
7801         memcpy (res, sig, MONO_SIZEOF_METHOD_SIGNATURE);
7802         res->param_count = sig->param_count + 1;
7803         for (i = 0; i < sig->param_count; ++i)
7804                 res->params [i] = sig->params [i];
7805         res->params [sig->param_count] = &mono_defaults.int_class->byval_arg;
7806         return res;
7807 }
7808
7809 /*
7810  * mono_method_to_ir:
7811  *
7812  *   Translate the .net IL into linear IR.
7813  */
7814 int
7815 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
7816                    MonoInst *return_var, MonoInst **inline_args, 
7817                    guint inline_offset, gboolean is_virtual_call)
7818 {
7819         MonoError error;
7820         MonoInst *ins, **sp, **stack_start;
7821         MonoBasicBlock *tblock = NULL, *init_localsbb = NULL;
7822         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
7823         MonoMethod *cmethod, *method_definition;
7824         MonoInst **arg_array;
7825         MonoMethodHeader *header;
7826         MonoImage *image;
7827         guint32 token, ins_flag;
7828         MonoClass *klass;
7829         MonoClass *constrained_class = NULL;
7830         unsigned char *ip, *end, *target, *err_pos;
7831         MonoMethodSignature *sig;
7832         MonoGenericContext *generic_context = NULL;
7833         MonoGenericContainer *generic_container = NULL;
7834         MonoType **param_types;
7835         int i, n, start_new_bblock, dreg;
7836         int num_calls = 0, inline_costs = 0;
7837         int breakpoint_id = 0;
7838         guint num_args;
7839         GSList *class_inits = NULL;
7840         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
7841         int context_used;
7842         gboolean init_locals, seq_points, skip_dead_blocks;
7843         gboolean sym_seq_points = FALSE;
7844         MonoDebugMethodInfo *minfo;
7845         MonoBitSet *seq_point_locs = NULL;
7846         MonoBitSet *seq_point_set_locs = NULL;
7847
7848         cfg->disable_inline = is_jit_optimizer_disabled (method);
7849
7850         /* serialization and xdomain stuff may need access to private fields and methods */
7851         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
7852         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
7853         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
7854         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
7855         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
7856         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
7857
7858         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
7859         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
7860         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
7861         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
7862         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
7863
7864         image = method->klass->image;
7865         header = mono_method_get_header (method);
7866         if (!header) {
7867                 MonoLoaderError *error;
7868
7869                 if ((error = mono_loader_get_last_error ())) {
7870                         mono_cfg_set_exception (cfg, error->exception_type);
7871                 } else {
7872                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
7873                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
7874                 }
7875                 goto exception_exit;
7876         }
7877         generic_container = mono_method_get_generic_container (method);
7878         sig = mono_method_signature (method);
7879         num_args = sig->hasthis + sig->param_count;
7880         ip = (unsigned char*)header->code;
7881         cfg->cil_start = ip;
7882         end = ip + header->code_size;
7883         cfg->stat_cil_code_size += header->code_size;
7884
7885         seq_points = cfg->gen_seq_points && cfg->method == method;
7886
7887         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
7888                 /* We could hit a seq point before attaching to the JIT (#8338) */
7889                 seq_points = FALSE;
7890         }
7891
7892         if (cfg->gen_sdb_seq_points && cfg->method == method) {
7893                 minfo = mono_debug_lookup_method (method);
7894                 if (minfo) {
7895                         MonoSymSeqPoint *sps;
7896                         int i, n_il_offsets;
7897
7898                         mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
7899                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7900                         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);
7901                         sym_seq_points = TRUE;
7902                         for (i = 0; i < n_il_offsets; ++i) {
7903                                 if (sps [i].il_offset < header->code_size)
7904                                         mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
7905                         }
7906                         g_free (sps);
7907                 } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
7908                         /* Methods without line number info like auto-generated property accessors */
7909                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
7910                         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);
7911                         sym_seq_points = TRUE;
7912                 }
7913         }
7914
7915         /* 
7916          * Methods without init_locals set could cause asserts in various passes
7917          * (#497220). To work around this, we emit dummy initialization opcodes
7918          * (OP_DUMMY_ICONST etc.) which generate no code. These are only supported
7919          * on some platforms.
7920          */
7921         if ((cfg->opt & MONO_OPT_UNSAFE) && cfg->backend->have_dummy_init)
7922                 init_locals = header->init_locals;
7923         else
7924                 init_locals = TRUE;
7925
7926         method_definition = method;
7927         while (method_definition->is_inflated) {
7928                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
7929                 method_definition = imethod->declaring;
7930         }
7931
7932         /* SkipVerification is not allowed if core-clr is enabled */
7933         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
7934                 dont_verify = TRUE;
7935                 dont_verify_stloc = TRUE;
7936         }
7937
7938         if (sig->is_inflated)
7939                 generic_context = mono_method_get_context (method);
7940         else if (generic_container)
7941                 generic_context = &generic_container->context;
7942         cfg->generic_context = generic_context;
7943
7944         if (!cfg->gshared)
7945                 g_assert (!sig->has_type_parameters);
7946
7947         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
7948                 g_assert (method->is_inflated);
7949                 g_assert (mono_method_get_context (method)->method_inst);
7950         }
7951         if (method->is_inflated && mono_method_get_context (method)->method_inst)
7952                 g_assert (sig->generic_param_count);
7953
7954         if (cfg->method == method) {
7955                 cfg->real_offset = 0;
7956         } else {
7957                 cfg->real_offset = inline_offset;
7958         }
7959
7960         cfg->cil_offset_to_bb = (MonoBasicBlock **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
7961         cfg->cil_offset_to_bb_len = header->code_size;
7962
7963         cfg->current_method = method;
7964
7965         if (cfg->verbose_level > 2)
7966                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
7967
7968         param_types = (MonoType **)mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
7969         if (sig->hasthis)
7970                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
7971         for (n = 0; n < sig->param_count; ++n)
7972                 param_types [n + sig->hasthis] = sig->params [n];
7973         cfg->arg_types = param_types;
7974
7975         cfg->dont_inline = g_list_prepend (cfg->dont_inline, method);
7976         if (cfg->method == method) {
7977
7978                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
7979                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
7980
7981                 /* ENTRY BLOCK */
7982                 NEW_BBLOCK (cfg, start_bblock);
7983                 cfg->bb_entry = start_bblock;
7984                 start_bblock->cil_code = NULL;
7985                 start_bblock->cil_length = 0;
7986
7987                 /* EXIT BLOCK */
7988                 NEW_BBLOCK (cfg, end_bblock);
7989                 cfg->bb_exit = end_bblock;
7990                 end_bblock->cil_code = NULL;
7991                 end_bblock->cil_length = 0;
7992                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7993                 g_assert (cfg->num_bblocks == 2);
7994
7995                 arg_array = cfg->args;
7996
7997                 if (header->num_clauses) {
7998                         cfg->spvars = g_hash_table_new (NULL, NULL);
7999                         cfg->exvars = g_hash_table_new (NULL, NULL);
8000                 }
8001                 /* handle exception clauses */
8002                 for (i = 0; i < header->num_clauses; ++i) {
8003                         MonoBasicBlock *try_bb;
8004                         MonoExceptionClause *clause = &header->clauses [i];
8005                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
8006
8007                         try_bb->real_offset = clause->try_offset;
8008                         try_bb->try_start = TRUE;
8009                         try_bb->region = ((i + 1) << 8) | clause->flags;
8010                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
8011                         tblock->real_offset = clause->handler_offset;
8012                         tblock->flags |= BB_EXCEPTION_HANDLER;
8013
8014                         /*
8015                          * Linking the try block with the EH block hinders inlining as we won't be able to 
8016                          * merge the bblocks from inlining and produce an artificial hole for no good reason.
8017                          */
8018                         if (COMPILE_LLVM (cfg))
8019                                 link_bblock (cfg, try_bb, tblock);
8020
8021                         if (*(ip + clause->handler_offset) == CEE_POP)
8022                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
8023
8024                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
8025                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
8026                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
8027                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8028                                 MONO_ADD_INS (tblock, ins);
8029
8030                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FILTER) {
8031                                         /* finally clauses already have a seq point */
8032                                         /* seq points for filter clauses are emitted below */
8033                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8034                                         MONO_ADD_INS (tblock, ins);
8035                                 }
8036
8037                                 /* todo: is a fault block unsafe to optimize? */
8038                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
8039                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
8040                         }
8041
8042                         /*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);
8043                           while (p < end) {
8044                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
8045                           }*/
8046                         /* catch and filter blocks get the exception object on the stack */
8047                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
8048                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8049
8050                                 /* mostly like handle_stack_args (), but just sets the input args */
8051                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
8052                                 tblock->in_scount = 1;
8053                                 tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8054                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8055
8056                                 cfg->cbb = tblock;
8057
8058 #ifdef MONO_CONTEXT_SET_LLVM_EXC_REG
8059                                 /* The EH code passes in the exception in a register to both JITted and LLVM compiled code */
8060                                 if (!cfg->compile_llvm) {
8061                                         MONO_INST_NEW (cfg, ins, OP_GET_EX_OBJ);
8062                                         ins->dreg = tblock->in_stack [0]->dreg;
8063                                         MONO_ADD_INS (tblock, ins);
8064                                 }
8065 #else
8066                                 MonoInst *dummy_use;
8067
8068                                 /* 
8069                                  * Add a dummy use for the exvar so its liveness info will be
8070                                  * correct.
8071                                  */
8072                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
8073 #endif
8074
8075                                 if (seq_points && clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8076                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
8077                                         MONO_ADD_INS (tblock, ins);
8078                                 }
8079                                 
8080                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
8081                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
8082                                         tblock->flags |= BB_EXCEPTION_HANDLER;
8083                                         tblock->real_offset = clause->data.filter_offset;
8084                                         tblock->in_scount = 1;
8085                                         tblock->in_stack = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
8086                                         /* The filter block shares the exvar with the handler block */
8087                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
8088                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
8089                                         MONO_ADD_INS (tblock, ins);
8090                                 }
8091                         }
8092
8093                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
8094                                         clause->data.catch_class &&
8095                                         cfg->gshared &&
8096                                         mono_class_check_context_used (clause->data.catch_class)) {
8097                                 /*
8098                                  * In shared generic code with catch
8099                                  * clauses containing type variables
8100                                  * the exception handling code has to
8101                                  * be able to get to the rgctx.
8102                                  * Therefore we have to make sure that
8103                                  * the vtable/mrgctx argument (for
8104                                  * static or generic methods) or the
8105                                  * "this" argument (for non-static
8106                                  * methods) are live.
8107                                  */
8108                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8109                                                 mini_method_get_context (method)->method_inst ||
8110                                                 method->klass->valuetype) {
8111                                         mono_get_vtable_var (cfg);
8112                                 } else {
8113                                         MonoInst *dummy_use;
8114
8115                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
8116                                 }
8117                         }
8118                 }
8119         } else {
8120                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
8121                 cfg->cbb = start_bblock;
8122                 cfg->args = arg_array;
8123                 mono_save_args (cfg, sig, inline_args);
8124         }
8125
8126         /* FIRST CODE BLOCK */
8127         NEW_BBLOCK (cfg, tblock);
8128         tblock->cil_code = ip;
8129         cfg->cbb = tblock;
8130         cfg->ip = ip;
8131
8132         ADD_BBLOCK (cfg, tblock);
8133
8134         if (cfg->method == method) {
8135                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
8136                 if (breakpoint_id) {
8137                         MONO_INST_NEW (cfg, ins, OP_BREAK);
8138                         MONO_ADD_INS (cfg->cbb, ins);
8139                 }
8140         }
8141
8142         /* we use a separate basic block for the initialization code */
8143         NEW_BBLOCK (cfg, init_localsbb);
8144         cfg->bb_init = init_localsbb;
8145         init_localsbb->real_offset = cfg->real_offset;
8146         start_bblock->next_bb = init_localsbb;
8147         init_localsbb->next_bb = cfg->cbb;
8148         link_bblock (cfg, start_bblock, init_localsbb);
8149         link_bblock (cfg, init_localsbb, cfg->cbb);
8150                 
8151         cfg->cbb = init_localsbb;
8152
8153         if (cfg->gsharedvt && cfg->method == method) {
8154                 MonoGSharedVtMethodInfo *info;
8155                 MonoInst *var, *locals_var;
8156                 int dreg;
8157
8158                 info = (MonoGSharedVtMethodInfo *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
8159                 info->method = cfg->method;
8160                 info->count_entries = 16;
8161                 info->entries = (MonoRuntimeGenericContextInfoTemplate *)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate) * info->count_entries);
8162                 cfg->gsharedvt_info = info;
8163
8164                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8165                 /* prevent it from being register allocated */
8166                 //var->flags |= MONO_INST_VOLATILE;
8167                 cfg->gsharedvt_info_var = var;
8168
8169                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
8170                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
8171
8172                 /* Allocate locals */
8173                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
8174                 /* prevent it from being register allocated */
8175                 //locals_var->flags |= MONO_INST_VOLATILE;
8176                 cfg->gsharedvt_locals_var = locals_var;
8177
8178                 dreg = alloc_ireg (cfg);
8179                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
8180
8181                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
8182                 ins->dreg = locals_var->dreg;
8183                 ins->sreg1 = dreg;
8184                 MONO_ADD_INS (cfg->cbb, ins);
8185                 cfg->gsharedvt_locals_var_ins = ins;
8186                 
8187                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
8188                 /*
8189                 if (init_locals)
8190                         ins->flags |= MONO_INST_INIT;
8191                 */
8192         }
8193
8194         if (mono_security_core_clr_enabled ()) {
8195                 /* check if this is native code, e.g. an icall or a p/invoke */
8196                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
8197                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
8198                         if (wrapped) {
8199                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
8200                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
8201
8202                                 /* if this ia a native call then it can only be JITted from platform code */
8203                                 if ((icall || pinvk) && method->klass && method->klass->image) {
8204                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
8205                                                 MonoException *ex = icall ? mono_get_exception_security () : 
8206                                                         mono_get_exception_method_access ();
8207                                                 emit_throw_exception (cfg, ex);
8208                                         }
8209                                 }
8210                         }
8211                 }
8212         }
8213
8214         CHECK_CFG_EXCEPTION;
8215
8216         if (header->code_size == 0)
8217                 UNVERIFIED;
8218
8219         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
8220                 ip = err_pos;
8221                 UNVERIFIED;
8222         }
8223
8224         if (cfg->method == method)
8225                 mono_debug_init_method (cfg, cfg->cbb, breakpoint_id);
8226
8227         for (n = 0; n < header->num_locals; ++n) {
8228                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
8229                         UNVERIFIED;
8230         }
8231         class_inits = NULL;
8232
8233         /* We force the vtable variable here for all shared methods
8234            for the possibility that they might show up in a stack
8235            trace where their exact instantiation is needed. */
8236         if (cfg->gshared && method == cfg->method) {
8237                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
8238                                 mini_method_get_context (method)->method_inst ||
8239                                 method->klass->valuetype) {
8240                         mono_get_vtable_var (cfg);
8241                 } else {
8242                         /* FIXME: Is there a better way to do this?
8243                            We need the variable live for the duration
8244                            of the whole method. */
8245                         cfg->args [0]->flags |= MONO_INST_VOLATILE;
8246                 }
8247         }
8248
8249         /* add a check for this != NULL to inlined methods */
8250         if (is_virtual_call) {
8251                 MonoInst *arg_ins;
8252
8253                 NEW_ARGLOAD (cfg, arg_ins, 0);
8254                 MONO_ADD_INS (cfg->cbb, arg_ins);
8255                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
8256         }
8257
8258         skip_dead_blocks = !dont_verify;
8259         if (skip_dead_blocks) {
8260                 original_bb = bb = mono_basic_block_split (method, &cfg->error);
8261                 CHECK_CFG_ERROR;
8262                 g_assert (bb);
8263         }
8264
8265         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
8266         stack_start = sp = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
8267
8268         ins_flag = 0;
8269         start_new_bblock = 0;
8270         while (ip < end) {
8271                 if (cfg->method == method)
8272                         cfg->real_offset = ip - header->code;
8273                 else
8274                         cfg->real_offset = inline_offset;
8275                 cfg->ip = ip;
8276
8277                 context_used = 0;
8278
8279                 if (start_new_bblock) {
8280                         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
8281                         if (start_new_bblock == 2) {
8282                                 g_assert (ip == tblock->cil_code);
8283                         } else {
8284                                 GET_BBLOCK (cfg, tblock, ip);
8285                         }
8286                         cfg->cbb->next_bb = tblock;
8287                         cfg->cbb = tblock;
8288                         start_new_bblock = 0;
8289                         for (i = 0; i < cfg->cbb->in_scount; ++i) {
8290                                 if (cfg->verbose_level > 3)
8291                                         printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8292                                 EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8293                                 *sp++ = ins;
8294                         }
8295                         if (class_inits)
8296                                 g_slist_free (class_inits);
8297                         class_inits = NULL;
8298                 } else {
8299                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != cfg->cbb)) {
8300                                 link_bblock (cfg, cfg->cbb, tblock);
8301                                 if (sp != stack_start) {
8302                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8303                                         sp = stack_start;
8304                                         CHECK_UNVERIFIABLE (cfg);
8305                                 }
8306                                 cfg->cbb->next_bb = tblock;
8307                                 cfg->cbb = tblock;
8308                                 for (i = 0; i < cfg->cbb->in_scount; ++i) {
8309                                         if (cfg->verbose_level > 3)
8310                                                 printf ("loading %d from temp %d\n", i, (int)cfg->cbb->in_stack [i]->inst_c0);
8311                                         EMIT_NEW_TEMPLOAD (cfg, ins, cfg->cbb->in_stack [i]->inst_c0);
8312                                         *sp++ = ins;
8313                                 }
8314                                 g_slist_free (class_inits);
8315                                 class_inits = NULL;
8316                         }
8317                 }
8318
8319                 if (skip_dead_blocks) {
8320                         int ip_offset = ip - header->code;
8321
8322                         if (ip_offset == bb->end)
8323                                 bb = bb->next;
8324
8325                         if (bb->dead) {
8326                                 int op_size = mono_opcode_size (ip, end);
8327                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
8328
8329                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
8330
8331                                 if (ip_offset + op_size == bb->end) {
8332                                         MONO_INST_NEW (cfg, ins, OP_NOP);
8333                                         MONO_ADD_INS (cfg->cbb, ins);
8334                                         start_new_bblock = 1;
8335                                 }
8336
8337                                 ip += op_size;
8338                                 continue;
8339                         }
8340                 }
8341                 /*
8342                  * Sequence points are points where the debugger can place a breakpoint.
8343                  * Currently, we generate these automatically at points where the IL
8344                  * stack is empty.
8345                  */
8346                 if (seq_points && ((!sym_seq_points && (sp == stack_start)) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
8347                         /*
8348                          * Make methods interruptable at the beginning, and at the targets of
8349                          * backward branches.
8350                          * Also, do this at the start of every bblock in methods with clauses too,
8351                          * to be able to handle instructions with inprecise control flow like
8352                          * throw/endfinally.
8353                          * Backward branches are handled at the end of method-to-ir ().
8354                          */
8355                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
8356                         gboolean sym_seq_point = sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code);
8357
8358                         /* Avoid sequence points on empty IL like .volatile */
8359                         // FIXME: Enable this
8360                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
8361                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
8362                         if ((sp != stack_start) && !sym_seq_point)
8363                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
8364                         MONO_ADD_INS (cfg->cbb, ins);
8365
8366                         if (sym_seq_points)
8367                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
8368                 }
8369
8370                 cfg->cbb->real_offset = cfg->real_offset;
8371
8372                 if ((cfg->method == method) && cfg->coverage_info) {
8373                         guint32 cil_offset = ip - header->code;
8374                         cfg->coverage_info->data [cil_offset].cil_code = ip;
8375
8376                         /* TODO: Use an increment here */
8377 #if defined(TARGET_X86)
8378                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
8379                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
8380                         ins->inst_imm = 1;
8381                         MONO_ADD_INS (cfg->cbb, ins);
8382 #else
8383                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
8384                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
8385 #endif
8386                 }
8387
8388                 if (cfg->verbose_level > 3)
8389                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8390
8391                 switch (*ip) {
8392                 case CEE_NOP:
8393                         if (seq_points && !sym_seq_points && sp != stack_start) {
8394                                 /*
8395                                  * The C# compiler uses these nops to notify the JIT that it should
8396                                  * insert seq points.
8397                                  */
8398                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
8399                                 MONO_ADD_INS (cfg->cbb, ins);
8400                         }
8401                         if (cfg->keep_cil_nops)
8402                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
8403                         else
8404                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8405                         ip++;
8406                         MONO_ADD_INS (cfg->cbb, ins);
8407                         break;
8408                 case CEE_BREAK:
8409                         if (should_insert_brekpoint (cfg->method)) {
8410                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
8411                         } else {
8412                                 MONO_INST_NEW (cfg, ins, OP_NOP);
8413                         }
8414                         ip++;
8415                         MONO_ADD_INS (cfg->cbb, ins);
8416                         break;
8417                 case CEE_LDARG_0:
8418                 case CEE_LDARG_1:
8419                 case CEE_LDARG_2:
8420                 case CEE_LDARG_3:
8421                         CHECK_STACK_OVF (1);
8422                         n = (*ip)-CEE_LDARG_0;
8423                         CHECK_ARG (n);
8424                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8425                         ip++;
8426                         *sp++ = ins;
8427                         break;
8428                 case CEE_LDLOC_0:
8429                 case CEE_LDLOC_1:
8430                 case CEE_LDLOC_2:
8431                 case CEE_LDLOC_3:
8432                         CHECK_STACK_OVF (1);
8433                         n = (*ip)-CEE_LDLOC_0;
8434                         CHECK_LOCAL (n);
8435                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8436                         ip++;
8437                         *sp++ = ins;
8438                         break;
8439                 case CEE_STLOC_0:
8440                 case CEE_STLOC_1:
8441                 case CEE_STLOC_2:
8442                 case CEE_STLOC_3: {
8443                         CHECK_STACK (1);
8444                         n = (*ip)-CEE_STLOC_0;
8445                         CHECK_LOCAL (n);
8446                         --sp;
8447                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
8448                                 UNVERIFIED;
8449                         emit_stloc_ir (cfg, sp, header, n);
8450                         ++ip;
8451                         inline_costs += 1;
8452                         break;
8453                         }
8454                 case CEE_LDARG_S:
8455                         CHECK_OPSIZE (2);
8456                         CHECK_STACK_OVF (1);
8457                         n = ip [1];
8458                         CHECK_ARG (n);
8459                         EMIT_NEW_ARGLOAD (cfg, ins, n);
8460                         *sp++ = ins;
8461                         ip += 2;
8462                         break;
8463                 case CEE_LDARGA_S:
8464                         CHECK_OPSIZE (2);
8465                         CHECK_STACK_OVF (1);
8466                         n = ip [1];
8467                         CHECK_ARG (n);
8468                         NEW_ARGLOADA (cfg, ins, n);
8469                         MONO_ADD_INS (cfg->cbb, ins);
8470                         *sp++ = ins;
8471                         ip += 2;
8472                         break;
8473                 case CEE_STARG_S:
8474                         CHECK_OPSIZE (2);
8475                         CHECK_STACK (1);
8476                         --sp;
8477                         n = ip [1];
8478                         CHECK_ARG (n);
8479                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
8480                                 UNVERIFIED;
8481                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
8482                         ip += 2;
8483                         break;
8484                 case CEE_LDLOC_S:
8485                         CHECK_OPSIZE (2);
8486                         CHECK_STACK_OVF (1);
8487                         n = ip [1];
8488                         CHECK_LOCAL (n);
8489                         EMIT_NEW_LOCLOAD (cfg, ins, n);
8490                         *sp++ = ins;
8491                         ip += 2;
8492                         break;
8493                 case CEE_LDLOCA_S: {
8494                         unsigned char *tmp_ip;
8495                         CHECK_OPSIZE (2);
8496                         CHECK_STACK_OVF (1);
8497                         CHECK_LOCAL (ip [1]);
8498
8499                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
8500                                 ip = tmp_ip;
8501                                 inline_costs += 1;
8502                                 break;
8503                         }
8504
8505                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
8506                         *sp++ = ins;
8507                         ip += 2;
8508                         break;
8509                 }
8510                 case CEE_STLOC_S:
8511                         CHECK_OPSIZE (2);
8512                         CHECK_STACK (1);
8513                         --sp;
8514                         CHECK_LOCAL (ip [1]);
8515                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
8516                                 UNVERIFIED;
8517                         emit_stloc_ir (cfg, sp, header, ip [1]);
8518                         ip += 2;
8519                         inline_costs += 1;
8520                         break;
8521                 case CEE_LDNULL:
8522                         CHECK_STACK_OVF (1);
8523                         EMIT_NEW_PCONST (cfg, ins, NULL);
8524                         ins->type = STACK_OBJ;
8525                         ++ip;
8526                         *sp++ = ins;
8527                         break;
8528                 case CEE_LDC_I4_M1:
8529                         CHECK_STACK_OVF (1);
8530                         EMIT_NEW_ICONST (cfg, ins, -1);
8531                         ++ip;
8532                         *sp++ = ins;
8533                         break;
8534                 case CEE_LDC_I4_0:
8535                 case CEE_LDC_I4_1:
8536                 case CEE_LDC_I4_2:
8537                 case CEE_LDC_I4_3:
8538                 case CEE_LDC_I4_4:
8539                 case CEE_LDC_I4_5:
8540                 case CEE_LDC_I4_6:
8541                 case CEE_LDC_I4_7:
8542                 case CEE_LDC_I4_8:
8543                         CHECK_STACK_OVF (1);
8544                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
8545                         ++ip;
8546                         *sp++ = ins;
8547                         break;
8548                 case CEE_LDC_I4_S:
8549                         CHECK_OPSIZE (2);
8550                         CHECK_STACK_OVF (1);
8551                         ++ip;
8552                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
8553                         ++ip;
8554                         *sp++ = ins;
8555                         break;
8556                 case CEE_LDC_I4:
8557                         CHECK_OPSIZE (5);
8558                         CHECK_STACK_OVF (1);
8559                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
8560                         ip += 5;
8561                         *sp++ = ins;
8562                         break;
8563                 case CEE_LDC_I8:
8564                         CHECK_OPSIZE (9);
8565                         CHECK_STACK_OVF (1);
8566                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
8567                         ins->type = STACK_I8;
8568                         ins->dreg = alloc_dreg (cfg, STACK_I8);
8569                         ++ip;
8570                         ins->inst_l = (gint64)read64 (ip);
8571                         MONO_ADD_INS (cfg->cbb, ins);
8572                         ip += 8;
8573                         *sp++ = ins;
8574                         break;
8575                 case CEE_LDC_R4: {
8576                         float *f;
8577                         gboolean use_aotconst = FALSE;
8578
8579 #ifdef TARGET_POWERPC
8580                         /* FIXME: Clean this up */
8581                         if (cfg->compile_aot)
8582                                 use_aotconst = TRUE;
8583 #endif
8584
8585                         /* FIXME: we should really allocate this only late in the compilation process */
8586                         f = (float *)mono_domain_alloc (cfg->domain, sizeof (float));
8587                         CHECK_OPSIZE (5);
8588                         CHECK_STACK_OVF (1);
8589
8590                         if (use_aotconst) {
8591                                 MonoInst *cons;
8592                                 int dreg;
8593
8594                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
8595
8596                                 dreg = alloc_freg (cfg);
8597                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
8598                                 ins->type = cfg->r4_stack_type;
8599                         } else {
8600                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
8601                                 ins->type = cfg->r4_stack_type;
8602                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8603                                 ins->inst_p0 = f;
8604                                 MONO_ADD_INS (cfg->cbb, ins);
8605                         }
8606                         ++ip;
8607                         readr4 (ip, f);
8608                         ip += 4;
8609                         *sp++ = ins;                    
8610                         break;
8611                 }
8612                 case CEE_LDC_R8: {
8613                         double *d;
8614                         gboolean use_aotconst = FALSE;
8615
8616 #ifdef TARGET_POWERPC
8617                         /* FIXME: Clean this up */
8618                         if (cfg->compile_aot)
8619                                 use_aotconst = TRUE;
8620 #endif
8621
8622                         /* FIXME: we should really allocate this only late in the compilation process */
8623                         d = (double *)mono_domain_alloc (cfg->domain, sizeof (double));
8624                         CHECK_OPSIZE (9);
8625                         CHECK_STACK_OVF (1);
8626
8627                         if (use_aotconst) {
8628                                 MonoInst *cons;
8629                                 int dreg;
8630
8631                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
8632
8633                                 dreg = alloc_freg (cfg);
8634                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
8635                                 ins->type = STACK_R8;
8636                         } else {
8637                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
8638                                 ins->type = STACK_R8;
8639                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
8640                                 ins->inst_p0 = d;
8641                                 MONO_ADD_INS (cfg->cbb, ins);
8642                         }
8643                         ++ip;
8644                         readr8 (ip, d);
8645                         ip += 8;
8646                         *sp++ = ins;
8647                         break;
8648                 }
8649                 case CEE_DUP: {
8650                         MonoInst *temp, *store;
8651                         CHECK_STACK (1);
8652                         CHECK_STACK_OVF (1);
8653                         sp--;
8654                         ins = *sp;
8655
8656                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
8657                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
8658
8659                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8660                         *sp++ = ins;
8661
8662                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
8663                         *sp++ = ins;
8664
8665                         ++ip;
8666                         inline_costs += 2;
8667                         break;
8668                 }
8669                 case CEE_POP:
8670                         CHECK_STACK (1);
8671                         ip++;
8672                         --sp;
8673
8674 #ifdef TARGET_X86
8675                         if (sp [0]->type == STACK_R8)
8676                                 /* we need to pop the value from the x86 FP stack */
8677                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
8678 #endif
8679                         break;
8680                 case CEE_JMP: {
8681                         MonoCallInst *call;
8682                         MonoMethodSignature *fsig;
8683                         int i, n;
8684
8685                         INLINE_FAILURE ("jmp");
8686                         GSHAREDVT_FAILURE (*ip);
8687
8688                         CHECK_OPSIZE (5);
8689                         if (stack_start != sp)
8690                                 UNVERIFIED;
8691                         token = read32 (ip + 1);
8692                         /* FIXME: check the signature matches */
8693                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8694
8695                         if (!cmethod || mono_loader_get_last_error ())
8696                                 LOAD_ERROR;
8697  
8698                         if (cfg->gshared && mono_method_check_context_used (cmethod))
8699                                 GENERIC_SHARING_FAILURE (CEE_JMP);
8700
8701                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
8702
8703                         fsig = mono_method_signature (cmethod);
8704                         n = fsig->param_count + fsig->hasthis;
8705                         if (cfg->llvm_only) {
8706                                 MonoInst **args;
8707
8708                                 args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8709                                 for (i = 0; i < n; ++i)
8710                                         EMIT_NEW_ARGLOAD (cfg, args [i], i);
8711                                 ins = mono_emit_method_call_full (cfg, cmethod, fsig, TRUE, args, NULL, NULL, NULL);
8712                                 /*
8713                                  * The code in mono-basic-block.c treats the rest of the code as dead, but we
8714                                  * have to emit a normal return since llvm expects it.
8715                                  */
8716                                 if (cfg->ret)
8717                                         emit_setret (cfg, ins);
8718                                 MONO_INST_NEW (cfg, ins, OP_BR);
8719                                 ins->inst_target_bb = end_bblock;
8720                                 MONO_ADD_INS (cfg->cbb, ins);
8721                                 link_bblock (cfg, cfg->cbb, end_bblock);
8722                                 ip += 5;
8723                                 break;
8724                         } else if (cfg->backend->have_op_tail_call) {
8725                                 /* Handle tail calls similarly to calls */
8726                                 DISABLE_AOT (cfg);
8727
8728                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
8729                                 call->method = cmethod;
8730                                 call->tail_call = TRUE;
8731                                 call->signature = mono_method_signature (cmethod);
8732                                 call->args = (MonoInst **)mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
8733                                 call->inst.inst_p0 = cmethod;
8734                                 for (i = 0; i < n; ++i)
8735                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
8736
8737                                 mono_arch_emit_call (cfg, call);
8738                                 cfg->param_area = MAX(cfg->param_area, call->stack_usage);
8739                                 MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
8740                         } else {
8741                                 for (i = 0; i < num_args; ++i)
8742                                         /* Prevent arguments from being optimized away */
8743                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
8744
8745                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8746                                 ins = (MonoInst*)call;
8747                                 ins->inst_p0 = cmethod;
8748                                 MONO_ADD_INS (cfg->cbb, ins);
8749                         }
8750
8751                         ip += 5;
8752                         start_new_bblock = 1;
8753                         break;
8754                 }
8755                 case CEE_CALLI: {
8756                         MonoInst *addr;
8757                         MonoMethodSignature *fsig;
8758
8759                         CHECK_OPSIZE (5);
8760                         token = read32 (ip + 1);
8761
8762                         ins = NULL;
8763
8764                         //GSHAREDVT_FAILURE (*ip);
8765                         cmethod = NULL;
8766                         CHECK_STACK (1);
8767                         --sp;
8768                         addr = *sp;
8769                         fsig = mini_get_signature (method, token, generic_context);
8770
8771                         if (method->dynamic && fsig->pinvoke) {
8772                                 MonoInst *args [3];
8773
8774                                 /*
8775                                  * This is a call through a function pointer using a pinvoke
8776                                  * signature. Have to create a wrapper and call that instead.
8777                                  * FIXME: This is very slow, need to create a wrapper at JIT time
8778                                  * instead based on the signature.
8779                                  */
8780                                 EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
8781                                 EMIT_NEW_PCONST (cfg, args [1], fsig);
8782                                 args [2] = addr;
8783                                 addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
8784                         }
8785
8786                         n = fsig->param_count + fsig->hasthis;
8787
8788                         CHECK_STACK (n);
8789
8790                         //g_assert (!virtual_ || fsig->hasthis);
8791
8792                         sp -= n;
8793
8794                         inline_costs += 10 * num_calls++;
8795
8796                         /*
8797                          * Making generic calls out of gsharedvt methods.
8798                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
8799                          * patching gshared method addresses into a gsharedvt method.
8800                          */
8801                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) {
8802                                 /*
8803                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8804                                  */
8805                                 MonoInst *callee = addr;
8806
8807                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8808                                         /* Not tested */
8809                                         GSHAREDVT_FAILURE (*ip);
8810
8811                                 addr = emit_get_rgctx_sig (cfg, context_used,
8812                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8813                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8814                                 goto calli_end;
8815                         }
8816
8817                         /* Prevent inlining of methods with indirect calls */
8818                         INLINE_FAILURE ("indirect call");
8819
8820                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8821                                 MonoJumpInfoType info_type;
8822                                 gpointer info_data;
8823
8824                                 /*
8825                                  * Instead of emitting an indirect call, emit a direct call
8826                                  * with the contents of the aotconst as the patch info.
8827                                  */
8828                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8829                                         info_type = (MonoJumpInfoType)addr->inst_c1;
8830                                         info_data = addr->inst_p0;
8831                                 } else {
8832                                         info_type = (MonoJumpInfoType)addr->inst_right->inst_c1;
8833                                         info_data = addr->inst_right->inst_left;
8834                                 }
8835
8836                                 if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8837                                         ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8838                                         NULLIFY_INS (addr);
8839                                         goto calli_end;
8840                                 }
8841                         }
8842                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
8843
8844                         calli_end:
8845
8846                         /* End of call, INS should contain the result of the call, if any */
8847
8848                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8849                                 g_assert (ins);
8850                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8851                         }
8852
8853                         CHECK_CFG_EXCEPTION;
8854
8855                         ip += 5;
8856                         ins_flag = 0;
8857                         constrained_class = NULL;
8858                         break;
8859                 }
8860                 case CEE_CALL:
8861                 case CEE_CALLVIRT: {
8862                         MonoInst *addr = NULL;
8863                         MonoMethodSignature *fsig = NULL;
8864                         int array_rank = 0;
8865                         int virtual_ = *ip == CEE_CALLVIRT;
8866                         gboolean pass_imt_from_rgctx = FALSE;
8867                         MonoInst *imt_arg = NULL;
8868                         MonoInst *keep_this_alive = NULL;
8869                         gboolean pass_vtable = FALSE;
8870                         gboolean pass_mrgctx = FALSE;
8871                         MonoInst *vtable_arg = NULL;
8872                         gboolean check_this = FALSE;
8873                         gboolean supported_tail_call = FALSE;
8874                         gboolean tail_call = FALSE;
8875                         gboolean need_seq_point = FALSE;
8876                         guint32 call_opcode = *ip;
8877                         gboolean emit_widen = TRUE;
8878                         gboolean push_res = TRUE;
8879                         gboolean skip_ret = FALSE;
8880                         gboolean delegate_invoke = FALSE;
8881                         gboolean direct_icall = FALSE;
8882                         gboolean constrained_partial_call = FALSE;
8883                         MonoMethod *cil_method;
8884
8885                         CHECK_OPSIZE (5);
8886                         token = read32 (ip + 1);
8887
8888                         ins = NULL;
8889
8890                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
8891                         cil_method = cmethod;
8892                                 
8893                         if (constrained_class) {
8894                                 if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8895                                         if (!mini_is_gsharedvt_klass (constrained_class)) {
8896                                                 g_assert (!cmethod->klass->valuetype);
8897                                                 if (!mini_type_is_reference (&constrained_class->byval_arg))
8898                                                         constrained_partial_call = TRUE;
8899                                         }
8900                                 }
8901
8902                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
8903                                         if (cfg->verbose_level > 2)
8904                                                 printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8905                                         if (!((constrained_class->byval_arg.type == MONO_TYPE_VAR ||
8906                                                    constrained_class->byval_arg.type == MONO_TYPE_MVAR) &&
8907                                                   cfg->gshared)) {
8908                                                 cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_class, generic_context, &cfg->error);
8909                                                 CHECK_CFG_ERROR;
8910                                         }
8911                                 } else {
8912                                         if (cfg->verbose_level > 2)
8913                                                 printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_class));
8914
8915                                         if ((constrained_class->byval_arg.type == MONO_TYPE_VAR || constrained_class->byval_arg.type == MONO_TYPE_MVAR) && cfg->gshared) {
8916                                                 /* 
8917                                                  * This is needed since get_method_constrained can't find 
8918                                                  * the method in klass representing a type var.
8919                                                  * The type var is guaranteed to be a reference type in this
8920                                                  * case.
8921                                                  */
8922                                                 if (!mini_is_gsharedvt_klass (constrained_class))
8923                                                         g_assert (!cmethod->klass->valuetype);
8924                                         } else {
8925                                                 cmethod = mono_get_method_constrained_checked (image, token, constrained_class, generic_context, &cil_method, &cfg->error);
8926                                                 CHECK_CFG_ERROR;
8927                                         }
8928                                 }
8929                         }
8930                                         
8931                         if (!cmethod || mono_loader_get_last_error ())
8932                                 LOAD_ERROR;
8933                         if (!dont_verify && !cfg->skip_visibility) {
8934                                 MonoMethod *target_method = cil_method;
8935                                 if (method->is_inflated) {
8936                                         target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
8937                                 }
8938                                 if (!mono_method_can_access_method (method_definition, target_method) &&
8939                                         !mono_method_can_access_method (method, cil_method))
8940                                         METHOD_ACCESS_FAILURE (method, cil_method);
8941                         }
8942
8943                         if (mono_security_core_clr_enabled ())
8944                                 ensure_method_is_allowed_to_call_method (cfg, method, cil_method);
8945
8946                         if (!virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
8947                                 /* MS.NET seems to silently convert this to a callvirt */
8948                                 virtual_ = 1;
8949
8950                         {
8951                                 /*
8952                                  * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
8953                                  * converts to a callvirt.
8954                                  *
8955                                  * tests/bug-515884.il is an example of this behavior
8956                                  */
8957                                 const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
8958                                 const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
8959                                 if (!virtual_ && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
8960                                         virtual_ = 1;
8961                         }
8962
8963                         if (!cmethod->klass->inited)
8964                                 if (!mono_class_init (cmethod->klass))
8965                                         TYPE_LOAD_ERROR (cmethod->klass);
8966
8967                         fsig = mono_method_signature (cmethod);
8968                         if (!fsig)
8969                                 LOAD_ERROR;
8970                         if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
8971                                 mini_class_is_system_array (cmethod->klass)) {
8972                                 array_rank = cmethod->klass->rank;
8973                         } else if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) && icall_is_direct_callable (cfg, cmethod)) {
8974                                 direct_icall = TRUE;
8975                         } else if (fsig->pinvoke) {
8976                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
8977                                 fsig = mono_method_signature (wrapper);
8978                         } else if (constrained_class) {
8979                         } else {
8980                                 fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
8981                                 CHECK_CFG_ERROR;
8982                         }
8983
8984                         /* See code below */
8985                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
8986                                 MonoBasicBlock *tbb;
8987
8988                                 GET_BBLOCK (cfg, tbb, ip + 5);
8989                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
8990                                         /*
8991                                          * We want to extend the try block to cover the call, but we can't do it if the
8992                                          * call is made directly since its followed by an exception check.
8993                                          */
8994                                         direct_icall = FALSE;
8995                                 }
8996                         }
8997
8998                         mono_save_token_info (cfg, image, token, cil_method);
8999
9000                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
9001                                 need_seq_point = TRUE;
9002
9003                         /* Don't support calls made using type arguments for now */
9004                         /*
9005                           if (cfg->gsharedvt) {
9006                           if (mini_is_gsharedvt_signature (fsig))
9007                           GSHAREDVT_FAILURE (*ip);
9008                           }
9009                         */
9010
9011                         if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
9012                                 g_assert_not_reached ();
9013
9014                         n = fsig->param_count + fsig->hasthis;
9015
9016                         if (!cfg->gshared && cmethod->klass->generic_container)
9017                                 UNVERIFIED;
9018
9019                         if (!cfg->gshared)
9020                                 g_assert (!mono_method_check_context_used (cmethod));
9021
9022                         CHECK_STACK (n);
9023
9024                         //g_assert (!virtual_ || fsig->hasthis);
9025
9026                         sp -= n;
9027
9028                         /*
9029                          * We have the `constrained.' prefix opcode.
9030                          */
9031                         if (constrained_class) {
9032                                 if (mini_is_gsharedvt_klass (constrained_class)) {
9033                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_class->valuetype && cmethod->klass->valuetype) {
9034                                                 /* The 'Own method' case below */
9035                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
9036                                                 /* 'The type parameter is instantiated as a reference type' case below. */
9037                                         } else {
9038                                                 ins = handle_constrained_gsharedvt_call (cfg, cmethod, fsig, sp, constrained_class, &emit_widen);
9039                                                 CHECK_CFG_EXCEPTION;
9040                                                 g_assert (ins);
9041                                                 goto call_end;
9042                                         }
9043                                 }
9044
9045                                 if (constrained_partial_call) {
9046                                         gboolean need_box = TRUE;
9047
9048                                         /*
9049                                          * The receiver is a valuetype, but the exact type is not known at compile time. This means the
9050                                          * called method is not known at compile time either. The called method could end up being
9051                                          * one of the methods on the parent classes (object/valuetype/enum), in which case we need
9052                                          * to box the receiver.
9053                                          * A simple solution would be to box always and make a normal virtual call, but that would
9054                                          * be bad performance wise.
9055                                          */
9056                                         if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE && cmethod->klass->generic_class) {
9057                                                 /*
9058                                                  * The parent classes implement no generic interfaces, so the called method will be a vtype method, so no boxing neccessary.
9059                                                  */
9060                                                 need_box = FALSE;
9061                                         }
9062
9063                                         if (!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9064                                                 /* The called method is not virtual, i.e. Object:GetType (), the receiver is a vtype, has to box */
9065                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9066                                                 ins->klass = constrained_class;
9067                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9068                                                 CHECK_CFG_EXCEPTION;
9069                                         } else if (need_box) {
9070                                                 MonoInst *box_type;
9071                                                 MonoBasicBlock *is_ref_bb, *end_bb;
9072                                                 MonoInst *nonbox_call;
9073
9074                                                 /*
9075                                                  * Determine at runtime whenever the called method is defined on object/valuetype/enum, and emit a boxing call
9076                                                  * if needed.
9077                                                  * FIXME: It is possible to inline the called method in a lot of cases, i.e. for T_INT,
9078                                                  * the no-box case goes to a method in Int32, while the box case goes to a method in Enum.
9079                                                  */
9080                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9081
9082                                                 NEW_BBLOCK (cfg, is_ref_bb);
9083                                                 NEW_BBLOCK (cfg, end_bb);
9084
9085                                                 box_type = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_BOX_TYPE);
9086                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, box_type->dreg, MONO_GSHAREDVT_BOX_TYPE_REF);
9087                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
9088
9089                                                 /* Non-ref case */
9090                                                 nonbox_call = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9091
9092                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9093
9094                                                 /* Ref case */
9095                                                 MONO_START_BB (cfg, is_ref_bb);
9096                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9097                                                 ins->klass = constrained_class;
9098                                                 sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9099                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9100
9101                                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9102
9103                                                 MONO_START_BB (cfg, end_bb);
9104                                                 cfg->cbb = end_bb;
9105
9106                                                 nonbox_call->dreg = ins->dreg;
9107                                                 goto call_end;
9108                                         } else {
9109                                                 g_assert (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
9110                                                 addr = emit_get_rgctx_virt_method (cfg, mono_class_check_context_used (constrained_class), constrained_class, cmethod, MONO_RGCTX_INFO_VIRT_METHOD_CODE);
9111                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9112                                                 goto call_end;
9113                                         }
9114                                 } else if (constrained_class->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
9115                                         /*
9116                                          * The type parameter is instantiated as a valuetype,
9117                                          * but that type doesn't override the method we're
9118                                          * calling, so we need to box `this'.
9119                                          */
9120                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9121                                         ins->klass = constrained_class;
9122                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9123                                         CHECK_CFG_EXCEPTION;
9124                                 } else if (!constrained_class->valuetype) {
9125                                         int dreg = alloc_ireg_ref (cfg);
9126
9127                                         /*
9128                                          * The type parameter is instantiated as a reference
9129                                          * type.  We have a managed pointer on the stack, so
9130                                          * we need to dereference it here.
9131                                          */
9132                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
9133                                         ins->type = STACK_OBJ;
9134                                         sp [0] = ins;
9135                                 } else {
9136                                         if (cmethod->klass->valuetype) {
9137                                                 /* Own method */
9138                                         } else {
9139                                                 /* Interface method */
9140                                                 int ioffset, slot;
9141
9142                                                 mono_class_setup_vtable (constrained_class);
9143                                                 CHECK_TYPELOAD (constrained_class);
9144                                                 ioffset = mono_class_interface_offset (constrained_class, cmethod->klass);
9145                                                 if (ioffset == -1)
9146                                                         TYPE_LOAD_ERROR (constrained_class);
9147                                                 slot = mono_method_get_vtable_slot (cmethod);
9148                                                 if (slot == -1)
9149                                                         TYPE_LOAD_ERROR (cmethod->klass);
9150                                                 cmethod = constrained_class->vtable [ioffset + slot];
9151
9152                                                 if (cmethod->klass == mono_defaults.enum_class) {
9153                                                         /* Enum implements some interfaces, so treat this as the first case */
9154                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_class->byval_arg, sp [0]->dreg, 0);
9155                                                         ins->klass = constrained_class;
9156                                                         sp [0] = handle_box (cfg, ins, constrained_class, mono_class_check_context_used (constrained_class));
9157                                                         CHECK_CFG_EXCEPTION;
9158                                                 }
9159                                         }
9160                                         virtual_ = 0;
9161                                 }
9162                                 constrained_class = NULL;
9163                         }
9164
9165                         if (check_call_signature (cfg, fsig, sp))
9166                                 UNVERIFIED;
9167
9168                         if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
9169                                 delegate_invoke = TRUE;
9170
9171                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
9172                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9173                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9174                                         emit_widen = FALSE;
9175                                 }
9176
9177                                 goto call_end;
9178                         }
9179
9180                         /* 
9181                          * If the callee is a shared method, then its static cctor
9182                          * might not get called after the call was patched.
9183                          */
9184                         if (cfg->gshared && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9185                                 emit_class_init (cfg, cmethod->klass);
9186                                 CHECK_TYPELOAD (cmethod->klass);
9187                         }
9188
9189                         check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
9190
9191                         if (cfg->gshared) {
9192                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
9193
9194                                 context_used = mini_method_check_context_used (cfg, cmethod);
9195
9196                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9197                                         /* Generic method interface
9198                                            calls are resolved via a
9199                                            helper function and don't
9200                                            need an imt. */
9201                                         if (!cmethod_context || !cmethod_context->method_inst)
9202                                                 pass_imt_from_rgctx = TRUE;
9203                                 }
9204
9205                                 /*
9206                                  * If a shared method calls another
9207                                  * shared method then the caller must
9208                                  * have a generic sharing context
9209                                  * because the magic trampoline
9210                                  * requires it.  FIXME: We shouldn't
9211                                  * have to force the vtable/mrgctx
9212                                  * variable here.  Instead there
9213                                  * should be a flag in the cfg to
9214                                  * request a generic sharing context.
9215                                  */
9216                                 if (context_used &&
9217                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
9218                                         mono_get_vtable_var (cfg);
9219                         }
9220
9221                         if (pass_vtable) {
9222                                 if (context_used) {
9223                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9224                                 } else {
9225                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9226
9227                                         CHECK_TYPELOAD (cmethod->klass);
9228                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9229                                 }
9230                         }
9231
9232                         if (pass_mrgctx) {
9233                                 g_assert (!vtable_arg);
9234
9235                                 if (!cfg->compile_aot) {
9236                                         /* 
9237                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
9238                                          * for type load errors before.
9239                                          */
9240                                         mono_class_setup_vtable (cmethod->klass);
9241                                         CHECK_TYPELOAD (cmethod->klass);
9242                                 }
9243
9244                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9245
9246                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
9247                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
9248                                          MONO_METHOD_IS_FINAL (cmethod)) &&
9249                                         !mono_class_is_marshalbyref (cmethod->klass)) {
9250                                         if (virtual_)
9251                                                 check_this = TRUE;
9252                                         virtual_ = 0;
9253                                 }
9254                         }
9255
9256                         if (pass_imt_from_rgctx) {
9257                                 g_assert (!pass_vtable);
9258
9259                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9260                                         cmethod, MONO_RGCTX_INFO_METHOD);
9261                         }
9262
9263                         if (check_this)
9264                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9265
9266                         /* Calling virtual generic methods */
9267                         if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) &&
9268                             !(MONO_METHOD_IS_FINAL (cmethod) && 
9269                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
9270                             fsig->generic_param_count && 
9271                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (fsig)) &&
9272                                 !cfg->llvm_only) {
9273                                 MonoInst *this_temp, *this_arg_temp, *store;
9274                                 MonoInst *iargs [4];
9275
9276                                 g_assert (fsig->is_inflated);
9277
9278                                 /* Prevent inlining of methods that contain indirect calls */
9279                                 INLINE_FAILURE ("virtual generic call");
9280
9281                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (fsig))
9282                                         GSHAREDVT_FAILURE (*ip);
9283
9284                                 if (cfg->backend->have_generalized_imt_thunk && cfg->backend->gshared_supported && cmethod->wrapper_type == MONO_WRAPPER_NONE) {
9285                                         g_assert (!imt_arg);
9286                                         if (!context_used)
9287                                                 g_assert (cmethod->is_inflated);
9288                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
9289                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9290                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
9291                                 } else {
9292                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
9293                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
9294                                         MONO_ADD_INS (cfg->cbb, store);
9295
9296                                         /* FIXME: This should be a managed pointer */
9297                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9298
9299                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
9300                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
9301                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
9302                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
9303                                         addr = mono_emit_jit_icall (cfg,
9304                                                                                                 mono_helper_compile_generic_method, iargs);
9305
9306                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
9307
9308                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
9309                                 }
9310
9311                                 goto call_end;
9312                         }
9313
9314                         /*
9315                          * Implement a workaround for the inherent races involved in locking:
9316                          * Monitor.Enter ()
9317                          * try {
9318                          * } finally {
9319                          *    Monitor.Exit ()
9320                          * }
9321                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
9322                          * try block, the Exit () won't be executed, see:
9323                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
9324                          * To work around this, we extend such try blocks to include the last x bytes
9325                          * of the Monitor.Enter () call.
9326                          */
9327                         if (cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
9328                                 MonoBasicBlock *tbb;
9329
9330                                 GET_BBLOCK (cfg, tbb, ip + 5);
9331                                 /* 
9332                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
9333                                  * from Monitor.Enter like ArgumentNullException.
9334                                  */
9335                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
9336                                         /* Mark this bblock as needing to be extended */
9337                                         tbb->extend_try_block = TRUE;
9338                                 }
9339                         }
9340
9341                         /* Conversion to a JIT intrinsic */
9342                         if ((cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
9343                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9344                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
9345                                         emit_widen = FALSE;
9346                                 }
9347                                 goto call_end;
9348                         }
9349
9350                         /* Inlining */
9351                         if ((cfg->opt & MONO_OPT_INLINE) &&
9352                                 (!virtual_ || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
9353                             mono_method_check_inlining (cfg, cmethod)) {
9354                                 int costs;
9355                                 gboolean always = FALSE;
9356
9357                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
9358                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
9359                                         /* Prevent inlining of methods that call wrappers */
9360                                         INLINE_FAILURE ("wrapper call");
9361                                         cmethod = mono_marshal_get_native_wrapper (cmethod, TRUE, FALSE);
9362                                         always = TRUE;
9363                                 }
9364
9365                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, always);
9366                                 if (costs) {
9367                                         cfg->real_offset += 5;
9368
9369                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9370                                                 /* *sp is already set by inline_method */
9371                                                 sp++;
9372                                                 push_res = FALSE;
9373                                         }
9374
9375                                         inline_costs += costs;
9376
9377                                         goto call_end;
9378                                 }
9379                         }
9380
9381                         /* Tail recursion elimination */
9382                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
9383                                 gboolean has_vtargs = FALSE;
9384                                 int i;
9385
9386                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9387                                 INLINE_FAILURE ("tail call");
9388
9389                                 /* keep it simple */
9390                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
9391                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
9392                                                 has_vtargs = TRUE;
9393                                 }
9394
9395                                 if (!has_vtargs) {
9396                                         for (i = 0; i < n; ++i)
9397                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9398                                         MONO_INST_NEW (cfg, ins, OP_BR);
9399                                         MONO_ADD_INS (cfg->cbb, ins);
9400                                         tblock = start_bblock->out_bb [0];
9401                                         link_bblock (cfg, cfg->cbb, tblock);
9402                                         ins->inst_target_bb = tblock;
9403                                         start_new_bblock = 1;
9404
9405                                         /* skip the CEE_RET, too */
9406                                         if (ip_in_bb (cfg, cfg->cbb, ip + 5))
9407                                                 skip_ret = TRUE;
9408                                         push_res = FALSE;
9409                                         goto call_end;
9410                                 }
9411                         }
9412
9413                         inline_costs += 10 * num_calls++;
9414
9415                         /*
9416                          * Making generic calls out of gsharedvt methods.
9417                          * This needs to be used for all generic calls, not just ones with a gsharedvt signature, to avoid
9418                          * patching gshared method addresses into a gsharedvt method.
9419                          */
9420                         if (cfg->gsharedvt && (mini_is_gsharedvt_signature (fsig) || cmethod->is_inflated || cmethod->klass->generic_class) &&
9421                                 !(cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)) {
9422                                 MonoRgctxInfoType info_type;
9423
9424                                 if (virtual_) {
9425                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
9426                                                 //GSHAREDVT_FAILURE (*ip);
9427                                         // disable for possible remoting calls
9428                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
9429                                                 GSHAREDVT_FAILURE (*ip);
9430                                         if (fsig->generic_param_count) {
9431                                                 /* virtual generic call */
9432                                                 g_assert (!imt_arg);
9433                                                 /* Same as the virtual generic case above */
9434                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9435                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9436                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
9437                                                 vtable_arg = NULL;
9438                                         } else if ((cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !imt_arg) {
9439                                                 /* This can happen when we call a fully instantiated iface method */
9440                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
9441                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
9442                                                 vtable_arg = NULL;
9443                                         }
9444                                 }
9445
9446                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
9447                                         keep_this_alive = sp [0];
9448
9449                                 if (virtual_ && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
9450                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
9451                                 else
9452                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
9453                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
9454
9455                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9456                                 goto call_end;
9457                         }
9458
9459                         /* Generic sharing */
9460
9461                         /*
9462                          * Use this if the callee is gsharedvt sharable too, since
9463                          * at runtime we might find an instantiation so the call cannot
9464                          * be patched (the 'no_patch' code path in mini-trampolines.c).
9465                          */
9466                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
9467                                 (!mono_method_is_generic_sharable_full (cmethod, TRUE, FALSE, FALSE) ||
9468                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
9469                                 (!virtual_ || MONO_METHOD_IS_FINAL (cmethod) ||
9470                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
9471                                 INLINE_FAILURE ("gshared");
9472
9473                                 g_assert (cfg->gshared && cmethod);
9474                                 g_assert (!addr);
9475
9476                                 /*
9477                                  * We are compiling a call to a
9478                                  * generic method from shared code,
9479                                  * which means that we have to look up
9480                                  * the method in the rgctx and do an
9481                                  * indirect call.
9482                                  */
9483                                 if (fsig->hasthis)
9484                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
9485
9486                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9487                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
9488                                 goto call_end;
9489                         }
9490
9491                         /* Direct calls to icalls */
9492                         if (direct_icall) {
9493                                 MonoMethod *wrapper;
9494                                 int costs;
9495
9496                                 /* Inline the wrapper */
9497                                 wrapper = mono_marshal_get_native_wrapper (cmethod, TRUE, cfg->compile_aot);
9498
9499                                 costs = inline_method (cfg, wrapper, fsig, sp, ip, cfg->real_offset, TRUE);
9500                                 g_assert (costs > 0);
9501                                 cfg->real_offset += 5;
9502
9503                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9504                                         /* *sp is already set by inline_method */
9505                                         sp++;
9506                                         push_res = FALSE;
9507                                 }
9508
9509                                 inline_costs += costs;
9510
9511                                 goto call_end;
9512                         }
9513                                         
9514                         /* Array methods */
9515                         if (array_rank) {
9516                                 MonoInst *addr;
9517
9518                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
9519                                         MonoInst *val = sp [fsig->param_count];
9520
9521                                         if (val->type == STACK_OBJ) {
9522                                                 MonoInst *iargs [2];
9523
9524                                                 iargs [0] = sp [0];
9525                                                 iargs [1] = val;
9526                                                 
9527                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
9528                                         }
9529                                         
9530                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
9531                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
9532                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
9533                                                 emit_write_barrier (cfg, addr, val);
9534                                         if (cfg->gen_write_barriers && mini_is_gsharedvt_klass (cmethod->klass))
9535                                                 GSHAREDVT_FAILURE (*ip);
9536                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
9537                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9538
9539                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
9540                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
9541                                         if (!cmethod->klass->element_class->valuetype && !readonly)
9542                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
9543                                         CHECK_TYPELOAD (cmethod->klass);
9544                                         
9545                                         readonly = FALSE;
9546                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
9547                                         ins = addr;
9548                                 } else {
9549                                         g_assert_not_reached ();
9550                                 }
9551
9552                                 emit_widen = FALSE;
9553                                 goto call_end;
9554                         }
9555
9556                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual_ ? sp [0] : NULL);
9557                         if (ins)
9558                                 goto call_end;
9559
9560                         /* Tail prefix / tail call optimization */
9561
9562                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
9563                         /* FIXME: runtime generic context pointer for jumps? */
9564                         /* FIXME: handle this for generic sharing eventually */
9565                         if ((ins_flag & MONO_INST_TAILCALL) &&
9566                                 !vtable_arg && !cfg->gshared && is_supported_tail_call (cfg, method, cmethod, fsig, call_opcode))
9567                                 supported_tail_call = TRUE;
9568
9569                         if (supported_tail_call) {
9570                                 MonoCallInst *call;
9571
9572                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
9573                                 INLINE_FAILURE ("tail call");
9574
9575                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
9576
9577                                 if (cfg->backend->have_op_tail_call) {
9578                                         /* Handle tail calls similarly to normal calls */
9579                                         tail_call = TRUE;
9580                                 } else {
9581                                         emit_instrumentation_call (cfg, mono_profiler_method_leave);
9582
9583                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
9584                                         call->tail_call = TRUE;
9585                                         call->method = cmethod;
9586                                         call->signature = mono_method_signature (cmethod);
9587
9588                                         /*
9589                                          * We implement tail calls by storing the actual arguments into the 
9590                                          * argument variables, then emitting a CEE_JMP.
9591                                          */
9592                                         for (i = 0; i < n; ++i) {
9593                                                 /* Prevent argument from being register allocated */
9594                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
9595                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
9596                                         }
9597                                         ins = (MonoInst*)call;
9598                                         ins->inst_p0 = cmethod;
9599                                         ins->inst_p1 = arg_array [0];
9600                                         MONO_ADD_INS (cfg->cbb, ins);
9601                                         link_bblock (cfg, cfg->cbb, end_bblock);
9602                                         start_new_bblock = 1;
9603
9604                                         // FIXME: Eliminate unreachable epilogs
9605
9606                                         /*
9607                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9608                                          * only reachable from this call.
9609                                          */
9610                                         GET_BBLOCK (cfg, tblock, ip + 5);
9611                                         if (tblock == cfg->cbb || tblock->in_count == 0)
9612                                                 skip_ret = TRUE;
9613                                         push_res = FALSE;
9614
9615                                         goto call_end;
9616                                 }
9617                         }
9618
9619                         /* 
9620                          * Synchronized wrappers.
9621                          * Its hard to determine where to replace a method with its synchronized
9622                          * wrapper without causing an infinite recursion. The current solution is
9623                          * to add the synchronized wrapper in the trampolines, and to
9624                          * change the called method to a dummy wrapper, and resolve that wrapper
9625                          * to the real method in mono_jit_compile_method ().
9626                          */
9627                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9628                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
9629                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
9630                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
9631                         }
9632
9633                         /*
9634                          * Interface calls in llvm-only mode are complicated becase the callee might need an rgctx arg,
9635                          * (i.e. its a vtype method), and there is no way to for the caller to know this at compile time.
9636                          * So we make resolve_iface_call return the rgctx, and do two calls with different signatures
9637                          * based on whenever there is an rgctx or not.
9638                          */
9639                         if (cfg->llvm_only && virtual_ && cmethod && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9640                                 MonoInst *args_buf [16], *icall_args [16];
9641                                 MonoInst **args;
9642                                 MonoBasicBlock *rgctx_bb, *end_bb;
9643                                 MonoInst *call1, *call2, *call_target;
9644                                 MonoMethodSignature *rgctx_sig;
9645                                 int rgctx_reg, tmp_reg;
9646
9647                                 MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9648
9649                                 NEW_BBLOCK (cfg, rgctx_bb);
9650                                 NEW_BBLOCK (cfg, end_bb);
9651
9652                                 // FIXME: Optimize this
9653
9654                                 guint32 imt_slot = mono_method_get_imt_slot (cmethod);
9655
9656                                 icall_args [0] = sp [0];
9657                                 EMIT_NEW_ICONST (cfg, icall_args [1], imt_slot);
9658                                 if (imt_arg) {
9659                                         icall_args [2] = imt_arg;
9660                                 } else {
9661                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_METHODCONST, cmethod);
9662                                         icall_args [2] = ins;
9663                                 }
9664
9665                                 rgctx_reg = alloc_preg (cfg);
9666                                 MONO_EMIT_NEW_PCONST (cfg, rgctx_reg, NULL);
9667                                 EMIT_NEW_VARLOADA_VREG (cfg, icall_args [3], rgctx_reg, &mono_defaults.int_class->byval_arg);
9668                                 //EMIT_NEW_PCONST (cfg, icall_args [3], NULL);
9669
9670                                 call_target = mono_emit_jit_icall (cfg, mono_resolve_iface_call, icall_args);
9671
9672                                 // FIXME: Only do this if needed (generic calls)
9673
9674                                 // Check whenever to pass an rgctx
9675                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rgctx_reg, 0);
9676                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBNE_UN, rgctx_bb);
9677                                 /* Non rgctx case */
9678                                 call1 = mono_emit_calli (cfg, fsig, sp, call_target, NULL, vtable_arg);
9679                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9680                                 /* Rgctx case */
9681                                 MONO_START_BB (cfg, rgctx_bb);
9682                                 /* Make a call with an rgctx */
9683                                 if (fsig->param_count + 2 < 16)
9684                                         args = args_buf;
9685                                 else
9686                                         args = (MonoInst **)mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (fsig->param_count + 2));
9687                                 args [0] = sp [0];
9688                                 for (i = 0; i < fsig->param_count; ++i)
9689                                         args [i + 1] = sp [i + 1];
9690                                 tmp_reg = alloc_preg (cfg);
9691                                 EMIT_NEW_UNALU (cfg, args [fsig->param_count + 1], OP_MOVE, tmp_reg, rgctx_reg);
9692                                 rgctx_sig = sig_to_rgctx_sig (fsig);
9693                                 call2 = mono_emit_calli (cfg, rgctx_sig, args, call_target, NULL, NULL);
9694                                 call2->dreg = call1->dreg;
9695                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
9696                                 /* End */
9697                                 MONO_START_BB (cfg, end_bb);
9698                                 ins = call1;
9699                                 goto call_end;
9700                         }
9701
9702                         /* Common call */
9703                         INLINE_FAILURE ("call");
9704                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual_ ? sp [0] : NULL,
9705                                                                                           imt_arg, vtable_arg);
9706
9707                         if (tail_call && !cfg->llvm_only) {
9708                                 link_bblock (cfg, cfg->cbb, end_bblock);
9709                                 start_new_bblock = 1;
9710
9711                                 // FIXME: Eliminate unreachable epilogs
9712
9713                                 /*
9714                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
9715                                  * only reachable from this call.
9716                                  */
9717                                 GET_BBLOCK (cfg, tblock, ip + 5);
9718                                 if (tblock == cfg->cbb || tblock->in_count == 0)
9719                                         skip_ret = TRUE;
9720                                 push_res = FALSE;
9721                         }
9722
9723                         call_end:
9724
9725                         /* End of call, INS should contain the result of the call, if any */
9726
9727                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
9728                                 g_assert (ins);
9729                                 if (emit_widen)
9730                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
9731                                 else
9732                                         *sp++ = ins;
9733                         }
9734
9735                         if (keep_this_alive) {
9736                                 MonoInst *dummy_use;
9737
9738                                 /* See mono_emit_method_call_full () */
9739                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
9740                         }
9741
9742                         CHECK_CFG_EXCEPTION;
9743
9744                         ip += 5;
9745                         if (skip_ret) {
9746                                 g_assert (*ip == CEE_RET);
9747                                 ip += 1;
9748                         }
9749                         ins_flag = 0;
9750                         constrained_class = NULL;
9751                         if (need_seq_point)
9752                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
9753                         break;
9754                 }
9755                 case CEE_RET:
9756                         if (cfg->method != method) {
9757                                 /* return from inlined method */
9758                                 /* 
9759                                  * If in_count == 0, that means the ret is unreachable due to
9760                                  * being preceeded by a throw. In that case, inline_method () will
9761                                  * handle setting the return value 
9762                                  * (test case: test_0_inline_throw ()).
9763                                  */
9764                                 if (return_var && cfg->cbb->in_count) {
9765                                         MonoType *ret_type = mono_method_signature (method)->ret;
9766
9767                                         MonoInst *store;
9768                                         CHECK_STACK (1);
9769                                         --sp;
9770
9771                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9772                                                 UNVERIFIED;
9773
9774                                         //g_assert (returnvar != -1);
9775                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
9776                                         cfg->ret_var_set = TRUE;
9777                                 } 
9778                         } else {
9779                                 emit_instrumentation_call (cfg, mono_profiler_method_leave);
9780
9781                                 if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only)
9782                                         emit_pop_lmf (cfg);
9783
9784                                 if (cfg->ret) {
9785                                         MonoType *ret_type = mini_get_underlying_type (mono_method_signature (method)->ret);
9786
9787                                         if (seq_points && !sym_seq_points) {
9788                                                 /* 
9789                                                  * Place a seq point here too even through the IL stack is not
9790                                                  * empty, so a step over on
9791                                                  * call <FOO>
9792                                                  * ret
9793                                                  * will work correctly.
9794                                                  */
9795                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
9796                                                 MONO_ADD_INS (cfg->cbb, ins);
9797                                         }
9798
9799                                         g_assert (!return_var);
9800                                         CHECK_STACK (1);
9801                                         --sp;
9802
9803                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
9804                                                 UNVERIFIED;
9805
9806                                         emit_setret (cfg, *sp);
9807                                 }
9808                         }
9809                         if (sp != stack_start)
9810                                 UNVERIFIED;
9811                         MONO_INST_NEW (cfg, ins, OP_BR);
9812                         ip++;
9813                         ins->inst_target_bb = end_bblock;
9814                         MONO_ADD_INS (cfg->cbb, ins);
9815                         link_bblock (cfg, cfg->cbb, end_bblock);
9816                         start_new_bblock = 1;
9817                         break;
9818                 case CEE_BR_S:
9819                         CHECK_OPSIZE (2);
9820                         MONO_INST_NEW (cfg, ins, OP_BR);
9821                         ip++;
9822                         target = ip + 1 + (signed char)(*ip);
9823                         ++ip;
9824                         GET_BBLOCK (cfg, tblock, target);
9825                         link_bblock (cfg, cfg->cbb, tblock);
9826                         ins->inst_target_bb = tblock;
9827                         if (sp != stack_start) {
9828                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9829                                 sp = stack_start;
9830                                 CHECK_UNVERIFIABLE (cfg);
9831                         }
9832                         MONO_ADD_INS (cfg->cbb, ins);
9833                         start_new_bblock = 1;
9834                         inline_costs += BRANCH_COST;
9835                         break;
9836                 case CEE_BEQ_S:
9837                 case CEE_BGE_S:
9838                 case CEE_BGT_S:
9839                 case CEE_BLE_S:
9840                 case CEE_BLT_S:
9841                 case CEE_BNE_UN_S:
9842                 case CEE_BGE_UN_S:
9843                 case CEE_BGT_UN_S:
9844                 case CEE_BLE_UN_S:
9845                 case CEE_BLT_UN_S:
9846                         CHECK_OPSIZE (2);
9847                         CHECK_STACK (2);
9848                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
9849                         ip++;
9850                         target = ip + 1 + *(signed char*)ip;
9851                         ip++;
9852
9853                         ADD_BINCOND (NULL);
9854
9855                         sp = stack_start;
9856                         inline_costs += BRANCH_COST;
9857                         break;
9858                 case CEE_BR:
9859                         CHECK_OPSIZE (5);
9860                         MONO_INST_NEW (cfg, ins, OP_BR);
9861                         ip++;
9862
9863                         target = ip + 4 + (gint32)read32(ip);
9864                         ip += 4;
9865                         GET_BBLOCK (cfg, tblock, target);
9866                         link_bblock (cfg, cfg->cbb, tblock);
9867                         ins->inst_target_bb = tblock;
9868                         if (sp != stack_start) {
9869                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9870                                 sp = stack_start;
9871                                 CHECK_UNVERIFIABLE (cfg);
9872                         }
9873
9874                         MONO_ADD_INS (cfg->cbb, ins);
9875
9876                         start_new_bblock = 1;
9877                         inline_costs += BRANCH_COST;
9878                         break;
9879                 case CEE_BRFALSE_S:
9880                 case CEE_BRTRUE_S:
9881                 case CEE_BRFALSE:
9882                 case CEE_BRTRUE: {
9883                         MonoInst *cmp;
9884                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
9885                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
9886                         guint32 opsize = is_short ? 1 : 4;
9887
9888                         CHECK_OPSIZE (opsize);
9889                         CHECK_STACK (1);
9890                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
9891                                 UNVERIFIED;
9892                         ip ++;
9893                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
9894                         ip += opsize;
9895
9896                         sp--;
9897
9898                         GET_BBLOCK (cfg, tblock, target);
9899                         link_bblock (cfg, cfg->cbb, tblock);
9900                         GET_BBLOCK (cfg, tblock, ip);
9901                         link_bblock (cfg, cfg->cbb, tblock);
9902
9903                         if (sp != stack_start) {
9904                                 handle_stack_args (cfg, stack_start, sp - stack_start);
9905                                 CHECK_UNVERIFIABLE (cfg);
9906                         }
9907
9908                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
9909                         cmp->sreg1 = sp [0]->dreg;
9910                         type_from_op (cfg, cmp, sp [0], NULL);
9911                         CHECK_TYPE (cmp);
9912
9913 #if SIZEOF_REGISTER == 4
9914                         if (cmp->opcode == OP_LCOMPARE_IMM) {
9915                                 /* Convert it to OP_LCOMPARE */
9916                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
9917                                 ins->type = STACK_I8;
9918                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
9919                                 ins->inst_l = 0;
9920                                 MONO_ADD_INS (cfg->cbb, ins);
9921                                 cmp->opcode = OP_LCOMPARE;
9922                                 cmp->sreg2 = ins->dreg;
9923                         }
9924 #endif
9925                         MONO_ADD_INS (cfg->cbb, cmp);
9926
9927                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
9928                         type_from_op (cfg, ins, sp [0], NULL);
9929                         MONO_ADD_INS (cfg->cbb, ins);
9930                         ins->inst_many_bb = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
9931                         GET_BBLOCK (cfg, tblock, target);
9932                         ins->inst_true_bb = tblock;
9933                         GET_BBLOCK (cfg, tblock, ip);
9934                         ins->inst_false_bb = tblock;
9935                         start_new_bblock = 2;
9936
9937                         sp = stack_start;
9938                         inline_costs += BRANCH_COST;
9939                         break;
9940                 }
9941                 case CEE_BEQ:
9942                 case CEE_BGE:
9943                 case CEE_BGT:
9944                 case CEE_BLE:
9945                 case CEE_BLT:
9946                 case CEE_BNE_UN:
9947                 case CEE_BGE_UN:
9948                 case CEE_BGT_UN:
9949                 case CEE_BLE_UN:
9950                 case CEE_BLT_UN:
9951                         CHECK_OPSIZE (5);
9952                         CHECK_STACK (2);
9953                         MONO_INST_NEW (cfg, ins, *ip);
9954                         ip++;
9955                         target = ip + 4 + (gint32)read32(ip);
9956                         ip += 4;
9957
9958                         ADD_BINCOND (NULL);
9959
9960                         sp = stack_start;
9961                         inline_costs += BRANCH_COST;
9962                         break;
9963                 case CEE_SWITCH: {
9964                         MonoInst *src1;
9965                         MonoBasicBlock **targets;
9966                         MonoBasicBlock *default_bblock;
9967                         MonoJumpInfoBBTable *table;
9968                         int offset_reg = alloc_preg (cfg);
9969                         int target_reg = alloc_preg (cfg);
9970                         int table_reg = alloc_preg (cfg);
9971                         int sum_reg = alloc_preg (cfg);
9972                         gboolean use_op_switch;
9973
9974                         CHECK_OPSIZE (5);
9975                         CHECK_STACK (1);
9976                         n = read32 (ip + 1);
9977                         --sp;
9978                         src1 = sp [0];
9979                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
9980                                 UNVERIFIED;
9981
9982                         ip += 5;
9983                         CHECK_OPSIZE (n * sizeof (guint32));
9984                         target = ip + n * sizeof (guint32);
9985
9986                         GET_BBLOCK (cfg, default_bblock, target);
9987                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
9988
9989                         targets = (MonoBasicBlock **)mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
9990                         for (i = 0; i < n; ++i) {
9991                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
9992                                 targets [i] = tblock;
9993                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
9994                                 ip += 4;
9995                         }
9996
9997                         if (sp != stack_start) {
9998                                 /* 
9999                                  * Link the current bb with the targets as well, so handle_stack_args
10000                                  * will set their in_stack correctly.
10001                                  */
10002                                 link_bblock (cfg, cfg->cbb, default_bblock);
10003                                 for (i = 0; i < n; ++i)
10004                                         link_bblock (cfg, cfg->cbb, targets [i]);
10005
10006                                 handle_stack_args (cfg, stack_start, sp - stack_start);
10007                                 sp = stack_start;
10008                                 CHECK_UNVERIFIABLE (cfg);
10009
10010                                 /* Undo the links */
10011                                 mono_unlink_bblock (cfg, cfg->cbb, default_bblock);
10012                                 for (i = 0; i < n; ++i)
10013                                         mono_unlink_bblock (cfg, cfg->cbb, targets [i]);
10014                         }
10015
10016                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
10017                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
10018
10019                         for (i = 0; i < n; ++i)
10020                                 link_bblock (cfg, cfg->cbb, targets [i]);
10021
10022                         table = (MonoJumpInfoBBTable *)mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
10023                         table->table = targets;
10024                         table->table_size = n;
10025
10026                         use_op_switch = FALSE;
10027 #ifdef TARGET_ARM
10028                         /* ARM implements SWITCH statements differently */
10029                         /* FIXME: Make it use the generic implementation */
10030                         if (!cfg->compile_aot)
10031                                 use_op_switch = TRUE;
10032 #endif
10033
10034                         if (COMPILE_LLVM (cfg))
10035                                 use_op_switch = TRUE;
10036
10037                         cfg->cbb->has_jump_table = 1;
10038
10039                         if (use_op_switch) {
10040                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
10041                                 ins->sreg1 = src1->dreg;
10042                                 ins->inst_p0 = table;
10043                                 ins->inst_many_bb = targets;
10044                                 ins->klass = (MonoClass *)GUINT_TO_POINTER (n);
10045                                 MONO_ADD_INS (cfg->cbb, ins);
10046                         } else {
10047                                 if (sizeof (gpointer) == 8)
10048                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
10049                                 else
10050                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
10051
10052 #if SIZEOF_REGISTER == 8
10053                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
10054                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
10055 #endif
10056
10057                                 if (cfg->compile_aot) {
10058                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
10059                                 } else {
10060                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
10061                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
10062                                         ins->inst_p0 = table;
10063                                         ins->dreg = table_reg;
10064                                         MONO_ADD_INS (cfg->cbb, ins);
10065                                 }
10066
10067                                 /* FIXME: Use load_memindex */
10068                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
10069                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
10070                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
10071                         }
10072                         start_new_bblock = 1;
10073                         inline_costs += (BRANCH_COST * 2);
10074                         break;
10075                 }
10076                 case CEE_LDIND_I1:
10077                 case CEE_LDIND_U1:
10078                 case CEE_LDIND_I2:
10079                 case CEE_LDIND_U2:
10080                 case CEE_LDIND_I4:
10081                 case CEE_LDIND_U4:
10082                 case CEE_LDIND_I8:
10083                 case CEE_LDIND_I:
10084                 case CEE_LDIND_R4:
10085                 case CEE_LDIND_R8:
10086                 case CEE_LDIND_REF:
10087                         CHECK_STACK (1);
10088                         --sp;
10089
10090                         switch (*ip) {
10091                         case CEE_LDIND_R4:
10092                         case CEE_LDIND_R8:
10093                                 dreg = alloc_freg (cfg);
10094                                 break;
10095                         case CEE_LDIND_I8:
10096                                 dreg = alloc_lreg (cfg);
10097                                 break;
10098                         case CEE_LDIND_REF:
10099                                 dreg = alloc_ireg_ref (cfg);
10100                                 break;
10101                         default:
10102                                 dreg = alloc_preg (cfg);
10103                         }
10104
10105                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
10106                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
10107                         if (*ip == CEE_LDIND_R4)
10108                                 ins->type = cfg->r4_stack_type;
10109                         ins->flags |= ins_flag;
10110                         MONO_ADD_INS (cfg->cbb, ins);
10111                         *sp++ = ins;
10112                         if (ins_flag & MONO_INST_VOLATILE) {
10113                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10114                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10115                         }
10116                         ins_flag = 0;
10117                         ++ip;
10118                         break;
10119                 case CEE_STIND_REF:
10120                 case CEE_STIND_I1:
10121                 case CEE_STIND_I2:
10122                 case CEE_STIND_I4:
10123                 case CEE_STIND_I8:
10124                 case CEE_STIND_R4:
10125                 case CEE_STIND_R8:
10126                 case CEE_STIND_I:
10127                         CHECK_STACK (2);
10128                         sp -= 2;
10129
10130                         if (ins_flag & MONO_INST_VOLATILE) {
10131                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
10132                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
10133                         }
10134
10135                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
10136                         ins->flags |= ins_flag;
10137                         ins_flag = 0;
10138
10139                         MONO_ADD_INS (cfg->cbb, ins);
10140
10141                         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)))
10142                                 emit_write_barrier (cfg, sp [0], sp [1]);
10143
10144                         inline_costs += 1;
10145                         ++ip;
10146                         break;
10147
10148                 case CEE_MUL:
10149                         CHECK_STACK (2);
10150
10151                         MONO_INST_NEW (cfg, ins, (*ip));
10152                         sp -= 2;
10153                         ins->sreg1 = sp [0]->dreg;
10154                         ins->sreg2 = sp [1]->dreg;
10155                         type_from_op (cfg, ins, sp [0], sp [1]);
10156                         CHECK_TYPE (ins);
10157                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10158
10159                         /* Use the immediate opcodes if possible */
10160                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
10161                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10162                                 if (imm_opcode != -1) {
10163                                         ins->opcode = imm_opcode;
10164                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
10165                                         ins->sreg2 = -1;
10166
10167                                         NULLIFY_INS (sp [1]);
10168                                 }
10169                         }
10170
10171                         MONO_ADD_INS ((cfg)->cbb, (ins));
10172
10173                         *sp++ = mono_decompose_opcode (cfg, ins);
10174                         ip++;
10175                         break;
10176                 case CEE_ADD:
10177                 case CEE_SUB:
10178                 case CEE_DIV:
10179                 case CEE_DIV_UN:
10180                 case CEE_REM:
10181                 case CEE_REM_UN:
10182                 case CEE_AND:
10183                 case CEE_OR:
10184                 case CEE_XOR:
10185                 case CEE_SHL:
10186                 case CEE_SHR:
10187                 case CEE_SHR_UN:
10188                         CHECK_STACK (2);
10189
10190                         MONO_INST_NEW (cfg, ins, (*ip));
10191                         sp -= 2;
10192                         ins->sreg1 = sp [0]->dreg;
10193                         ins->sreg2 = sp [1]->dreg;
10194                         type_from_op (cfg, ins, sp [0], sp [1]);
10195                         CHECK_TYPE (ins);
10196                         add_widen_op (cfg, ins, &sp [0], &sp [1]);
10197                         ins->dreg = alloc_dreg ((cfg), (MonoStackType)(ins)->type);
10198
10199                         /* FIXME: Pass opcode to is_inst_imm */
10200
10201                         /* Use the immediate opcodes if possible */
10202                         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)) {
10203                                 int imm_opcode;
10204
10205                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
10206 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10207                                 /* Keep emulated opcodes which are optimized away later */
10208                                 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) {
10209                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
10210                                 }
10211 #endif
10212                                 if (imm_opcode != -1) {
10213                                         ins->opcode = imm_opcode;
10214                                         if (sp [1]->opcode == OP_I8CONST) {
10215 #if SIZEOF_REGISTER == 8
10216                                                 ins->inst_imm = sp [1]->inst_l;
10217 #else
10218                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
10219                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
10220 #endif
10221                                         }
10222                                         else
10223                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
10224                                         ins->sreg2 = -1;
10225
10226                                         /* Might be followed by an instruction added by add_widen_op */
10227                                         if (sp [1]->next == NULL)
10228                                                 NULLIFY_INS (sp [1]);
10229                                 }
10230                         }
10231                         MONO_ADD_INS ((cfg)->cbb, (ins));
10232
10233                         *sp++ = mono_decompose_opcode (cfg, ins);
10234                         ip++;
10235                         break;
10236                 case CEE_NEG:
10237                 case CEE_NOT:
10238                 case CEE_CONV_I1:
10239                 case CEE_CONV_I2:
10240                 case CEE_CONV_I4:
10241                 case CEE_CONV_R4:
10242                 case CEE_CONV_R8:
10243                 case CEE_CONV_U4:
10244                 case CEE_CONV_I8:
10245                 case CEE_CONV_U8:
10246                 case CEE_CONV_OVF_I8:
10247                 case CEE_CONV_OVF_U8:
10248                 case CEE_CONV_R_UN:
10249                         CHECK_STACK (1);
10250
10251                         /* Special case this earlier so we have long constants in the IR */
10252                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
10253                                 int data = sp [-1]->inst_c0;
10254                                 sp [-1]->opcode = OP_I8CONST;
10255                                 sp [-1]->type = STACK_I8;
10256 #if SIZEOF_REGISTER == 8
10257                                 if ((*ip) == CEE_CONV_U8)
10258                                         sp [-1]->inst_c0 = (guint32)data;
10259                                 else
10260                                         sp [-1]->inst_c0 = data;
10261 #else
10262                                 sp [-1]->inst_ls_word = data;
10263                                 if ((*ip) == CEE_CONV_U8)
10264                                         sp [-1]->inst_ms_word = 0;
10265                                 else
10266                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
10267 #endif
10268                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
10269                         }
10270                         else {
10271                                 ADD_UNOP (*ip);
10272                         }
10273                         ip++;
10274                         break;
10275                 case CEE_CONV_OVF_I4:
10276                 case CEE_CONV_OVF_I1:
10277                 case CEE_CONV_OVF_I2:
10278                 case CEE_CONV_OVF_I:
10279                 case CEE_CONV_OVF_U:
10280                         CHECK_STACK (1);
10281
10282                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10283                                 ADD_UNOP (CEE_CONV_OVF_I8);
10284                                 ADD_UNOP (*ip);
10285                         } else {
10286                                 ADD_UNOP (*ip);
10287                         }
10288                         ip++;
10289                         break;
10290                 case CEE_CONV_OVF_U1:
10291                 case CEE_CONV_OVF_U2:
10292                 case CEE_CONV_OVF_U4:
10293                         CHECK_STACK (1);
10294
10295                         if (sp [-1]->type == STACK_R8 || sp [-1]->type == STACK_R4) {
10296                                 ADD_UNOP (CEE_CONV_OVF_U8);
10297                                 ADD_UNOP (*ip);
10298                         } else {
10299                                 ADD_UNOP (*ip);
10300                         }
10301                         ip++;
10302                         break;
10303                 case CEE_CONV_OVF_I1_UN:
10304                 case CEE_CONV_OVF_I2_UN:
10305                 case CEE_CONV_OVF_I4_UN:
10306                 case CEE_CONV_OVF_I8_UN:
10307                 case CEE_CONV_OVF_U1_UN:
10308                 case CEE_CONV_OVF_U2_UN:
10309                 case CEE_CONV_OVF_U4_UN:
10310                 case CEE_CONV_OVF_U8_UN:
10311                 case CEE_CONV_OVF_I_UN:
10312                 case CEE_CONV_OVF_U_UN:
10313                 case CEE_CONV_U2:
10314                 case CEE_CONV_U1:
10315                 case CEE_CONV_I:
10316                 case CEE_CONV_U:
10317                         CHECK_STACK (1);
10318                         ADD_UNOP (*ip);
10319                         CHECK_CFG_EXCEPTION;
10320                         ip++;
10321                         break;
10322                 case CEE_ADD_OVF:
10323                 case CEE_ADD_OVF_UN:
10324                 case CEE_MUL_OVF:
10325                 case CEE_MUL_OVF_UN:
10326                 case CEE_SUB_OVF:
10327                 case CEE_SUB_OVF_UN:
10328                         CHECK_STACK (2);
10329                         ADD_BINOP (*ip);
10330                         ip++;
10331                         break;
10332                 case CEE_CPOBJ:
10333                         GSHAREDVT_FAILURE (*ip);
10334                         CHECK_OPSIZE (5);
10335                         CHECK_STACK (2);
10336                         token = read32 (ip + 1);
10337                         klass = mini_get_class (method, token, generic_context);
10338                         CHECK_TYPELOAD (klass);
10339                         sp -= 2;
10340                         if (generic_class_is_reference_type (cfg, klass)) {
10341                                 MonoInst *store, *load;
10342                                 int dreg = alloc_ireg_ref (cfg);
10343
10344                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
10345                                 load->flags |= ins_flag;
10346                                 MONO_ADD_INS (cfg->cbb, load);
10347
10348                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
10349                                 store->flags |= ins_flag;
10350                                 MONO_ADD_INS (cfg->cbb, store);
10351
10352                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
10353                                         emit_write_barrier (cfg, sp [0], sp [1]);
10354                         } else {
10355                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10356                         }
10357                         ins_flag = 0;
10358                         ip += 5;
10359                         break;
10360                 case CEE_LDOBJ: {
10361                         int loc_index = -1;
10362                         int stloc_len = 0;
10363
10364                         CHECK_OPSIZE (5);
10365                         CHECK_STACK (1);
10366                         --sp;
10367                         token = read32 (ip + 1);
10368                         klass = mini_get_class (method, token, generic_context);
10369                         CHECK_TYPELOAD (klass);
10370
10371                         /* Optimize the common ldobj+stloc combination */
10372                         switch (ip [5]) {
10373                         case CEE_STLOC_S:
10374                                 loc_index = ip [6];
10375                                 stloc_len = 2;
10376                                 break;
10377                         case CEE_STLOC_0:
10378                         case CEE_STLOC_1:
10379                         case CEE_STLOC_2:
10380                         case CEE_STLOC_3:
10381                                 loc_index = ip [5] - CEE_STLOC_0;
10382                                 stloc_len = 1;
10383                                 break;
10384                         default:
10385                                 break;
10386                         }
10387
10388                         if ((loc_index != -1) && ip_in_bb (cfg, cfg->cbb, ip + 5)) {
10389                                 CHECK_LOCAL (loc_index);
10390
10391                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10392                                 ins->dreg = cfg->locals [loc_index]->dreg;
10393                                 ins->flags |= ins_flag;
10394                                 ip += 5;
10395                                 ip += stloc_len;
10396                                 if (ins_flag & MONO_INST_VOLATILE) {
10397                                         /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10398                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10399                                 }
10400                                 ins_flag = 0;
10401                                 break;
10402                         }
10403
10404                         /* Optimize the ldobj+stobj combination */
10405                         /* The reference case ends up being a load+store anyway */
10406                         /* Skip this if the operation is volatile. */
10407                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass) && !(ins_flag & MONO_INST_VOLATILE)) {
10408                                 CHECK_STACK (1);
10409
10410                                 sp --;
10411
10412                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
10413
10414                                 ip += 5 + 5;
10415                                 ins_flag = 0;
10416                                 break;
10417                         }
10418
10419                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
10420                         ins->flags |= ins_flag;
10421                         *sp++ = ins;
10422
10423                         if (ins_flag & MONO_INST_VOLATILE) {
10424                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
10425                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
10426                         }
10427
10428                         ip += 5;
10429                         ins_flag = 0;
10430                         inline_costs += 1;
10431                         break;
10432                 }
10433                 case CEE_LDSTR:
10434                         CHECK_STACK_OVF (1);
10435                         CHECK_OPSIZE (5);
10436                         n = read32 (ip + 1);
10437
10438                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
10439                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
10440                                 ins->type = STACK_OBJ;
10441                                 *sp = ins;
10442                         }
10443                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
10444                                 MonoInst *iargs [1];
10445                                 char *str = (char *)mono_method_get_wrapper_data (method, n);
10446
10447                                 if (cfg->compile_aot)
10448                                         EMIT_NEW_LDSTRLITCONST (cfg, iargs [0], str);
10449                                 else
10450                                         EMIT_NEW_PCONST (cfg, iargs [0], str);
10451                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
10452                         } else {
10453                                 if (cfg->opt & MONO_OPT_SHARED) {
10454                                         MonoInst *iargs [3];
10455
10456                                         if (cfg->compile_aot) {
10457                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
10458                                         }
10459                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10460                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
10461                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
10462                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
10463                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10464                                 } else {
10465                                         if (cfg->cbb->out_of_line) {
10466                                                 MonoInst *iargs [2];
10467
10468                                                 if (image == mono_defaults.corlib) {
10469                                                         /* 
10470                                                          * Avoid relocations in AOT and save some space by using a 
10471                                                          * version of helper_ldstr specialized to mscorlib.
10472                                                          */
10473                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
10474                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
10475                                                 } else {
10476                                                         /* Avoid creating the string object */
10477                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10478                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
10479                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
10480                                                 }
10481                                         } 
10482                                         else
10483                                         if (cfg->compile_aot) {
10484                                                 NEW_LDSTRCONST (cfg, ins, image, n);
10485                                                 *sp = ins;
10486                                                 MONO_ADD_INS (cfg->cbb, ins);
10487                                         } 
10488                                         else {
10489                                                 NEW_PCONST (cfg, ins, NULL);
10490                                                 ins->type = STACK_OBJ;
10491                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
10492                                                 if (!ins->inst_p0)
10493                                                         OUT_OF_MEMORY_FAILURE;
10494
10495                                                 *sp = ins;
10496                                                 MONO_ADD_INS (cfg->cbb, ins);
10497                                         }
10498                                 }
10499                         }
10500
10501                         sp++;
10502                         ip += 5;
10503                         break;
10504                 case CEE_NEWOBJ: {
10505                         MonoInst *iargs [2];
10506                         MonoMethodSignature *fsig;
10507                         MonoInst this_ins;
10508                         MonoInst *alloc;
10509                         MonoInst *vtable_arg = NULL;
10510
10511                         CHECK_OPSIZE (5);
10512                         token = read32 (ip + 1);
10513                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
10514                         if (!cmethod || mono_loader_get_last_error ())
10515                                 LOAD_ERROR;
10516                         fsig = mono_method_get_signature_checked (cmethod, image, token, generic_context, &cfg->error);
10517                         CHECK_CFG_ERROR;
10518
10519                         mono_save_token_info (cfg, image, token, cmethod);
10520
10521                         if (!mono_class_init (cmethod->klass))
10522                                 TYPE_LOAD_ERROR (cmethod->klass);
10523
10524                         context_used = mini_method_check_context_used (cfg, cmethod);
10525
10526                         if (mono_security_core_clr_enabled ())
10527                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
10528
10529                         if (cfg->gshared && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
10530                                 emit_class_init (cfg, cmethod->klass);
10531                                 CHECK_TYPELOAD (cmethod->klass);
10532                         }
10533
10534                         /*
10535                         if (cfg->gsharedvt) {
10536                                 if (mini_is_gsharedvt_variable_signature (sig))
10537                                         GSHAREDVT_FAILURE (*ip);
10538                         }
10539                         */
10540
10541                         n = fsig->param_count;
10542                         CHECK_STACK (n);
10543
10544                         /* 
10545                          * Generate smaller code for the common newobj <exception> instruction in
10546                          * argument checking code.
10547                          */
10548                         if (cfg->cbb->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
10549                                 is_exception_class (cmethod->klass) && n <= 2 &&
10550                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
10551                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
10552                                 MonoInst *iargs [3];
10553
10554                                 sp -= n;
10555
10556                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
10557                                 switch (n) {
10558                                 case 0:
10559                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
10560                                         break;
10561                                 case 1:
10562                                         iargs [1] = sp [0];
10563                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
10564                                         break;
10565                                 case 2:
10566                                         iargs [1] = sp [0];
10567                                         iargs [2] = sp [1];
10568                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
10569                                         break;
10570                                 default:
10571                                         g_assert_not_reached ();
10572                                 }
10573
10574                                 ip += 5;
10575                                 inline_costs += 5;
10576                                 break;
10577                         }
10578
10579                         /* move the args to allow room for 'this' in the first position */
10580                         while (n--) {
10581                                 --sp;
10582                                 sp [1] = sp [0];
10583                         }
10584
10585                         /* check_call_signature () requires sp[0] to be set */
10586                         this_ins.type = STACK_OBJ;
10587                         sp [0] = &this_ins;
10588                         if (check_call_signature (cfg, fsig, sp))
10589                                 UNVERIFIED;
10590
10591                         iargs [0] = NULL;
10592
10593                         if (mini_class_is_system_array (cmethod->klass)) {
10594                                 *sp = emit_get_rgctx_method (cfg, context_used,
10595                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
10596
10597                                 /* Avoid varargs in the common case */
10598                                 if (fsig->param_count == 1)
10599                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
10600                                 else if (fsig->param_count == 2)
10601                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
10602                                 else if (fsig->param_count == 3)
10603                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
10604                                 else if (fsig->param_count == 4)
10605                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
10606                                 else
10607                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
10608                         } else if (cmethod->string_ctor) {
10609                                 g_assert (!context_used);
10610                                 g_assert (!vtable_arg);
10611                                 /* we simply pass a null pointer */
10612                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
10613                                 /* now call the string ctor */
10614                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
10615                         } else {
10616                                 if (cmethod->klass->valuetype) {
10617                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
10618                                         emit_init_rvar (cfg, iargs [0]->dreg, &cmethod->klass->byval_arg);
10619                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
10620
10621                                         alloc = NULL;
10622
10623                                         /* 
10624                                          * The code generated by mini_emit_virtual_call () expects
10625                                          * iargs [0] to be a boxed instance, but luckily the vcall
10626                                          * will be transformed into a normal call there.
10627                                          */
10628                                 } else if (context_used) {
10629                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
10630                                         *sp = alloc;
10631                                 } else {
10632                                         MonoVTable *vtable = NULL;
10633
10634                                         if (!cfg->compile_aot)
10635                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
10636                                         CHECK_TYPELOAD (cmethod->klass);
10637
10638                                         /*
10639                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
10640                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
10641                                          * As a workaround, we call class cctors before allocating objects.
10642                                          */
10643                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
10644                                                 emit_class_init (cfg, cmethod->klass);
10645                                                 if (cfg->verbose_level > 2)
10646                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
10647                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
10648                                         }
10649
10650                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
10651                                         *sp = alloc;
10652                                 }
10653                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
10654
10655                                 if (alloc)
10656                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
10657
10658                                 /* Now call the actual ctor */
10659                                 handle_ctor_call (cfg, cmethod, fsig, context_used, sp, ip, &inline_costs);
10660                                 CHECK_CFG_EXCEPTION;
10661                         }
10662
10663                         if (alloc == NULL) {
10664                                 /* Valuetype */
10665                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
10666                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
10667                                 *sp++= ins;
10668                         } else {
10669                                 *sp++ = alloc;
10670                         }
10671                         
10672                         ip += 5;
10673                         inline_costs += 5;
10674                         if (!(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip - header->code)))
10675                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
10676                         break;
10677                 }
10678                 case CEE_CASTCLASS:
10679                         CHECK_STACK (1);
10680                         --sp;
10681                         CHECK_OPSIZE (5);
10682                         token = read32 (ip + 1);
10683                         klass = mini_get_class (method, token, generic_context);
10684                         CHECK_TYPELOAD (klass);
10685                         if (sp [0]->type != STACK_OBJ)
10686                                 UNVERIFIED;
10687
10688                         ins = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10689                         CHECK_CFG_EXCEPTION;
10690
10691                         *sp ++ = ins;
10692                         ip += 5;
10693                         break;
10694                 case CEE_ISINST: {
10695                         CHECK_STACK (1);
10696                         --sp;
10697                         CHECK_OPSIZE (5);
10698                         token = read32 (ip + 1);
10699                         klass = mini_get_class (method, token, generic_context);
10700                         CHECK_TYPELOAD (klass);
10701                         if (sp [0]->type != STACK_OBJ)
10702                                 UNVERIFIED;
10703  
10704                         context_used = mini_class_check_context_used (cfg, klass);
10705
10706                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
10707                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
10708                                 MonoInst *args [3];
10709                                 int idx;
10710
10711                                 /* obj */
10712                                 args [0] = *sp;
10713
10714                                 /* klass */
10715                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
10716
10717                                 /* inline cache*/
10718                                 idx = get_castclass_cache_idx (cfg);
10719                                 args [2] = emit_runtime_constant (cfg, MONO_PATCH_INFO_CASTCLASS_CACHE, GINT_TO_POINTER (idx));
10720
10721                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
10722                                 ip += 5;
10723                                 inline_costs += 2;
10724                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
10725                                 MonoMethod *mono_isinst;
10726                                 MonoInst *iargs [1];
10727                                 int costs;
10728
10729                                 mono_isinst = mono_marshal_get_isinst (klass); 
10730                                 iargs [0] = sp [0];
10731
10732                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
10733                                                                            iargs, ip, cfg->real_offset, TRUE);
10734                                 CHECK_CFG_EXCEPTION;
10735                                 g_assert (costs > 0);
10736                                 
10737                                 ip += 5;
10738                                 cfg->real_offset += 5;
10739
10740                                 *sp++= iargs [0];
10741
10742                                 inline_costs += costs;
10743                         }
10744                         else {
10745                                 ins = handle_isinst (cfg, klass, *sp, context_used);
10746                                 CHECK_CFG_EXCEPTION;
10747                                 *sp ++ = ins;
10748                                 ip += 5;
10749                         }
10750                         break;
10751                 }
10752                 case CEE_UNBOX_ANY: {
10753                         MonoInst *res, *addr;
10754
10755                         CHECK_STACK (1);
10756                         --sp;
10757                         CHECK_OPSIZE (5);
10758                         token = read32 (ip + 1);
10759                         klass = mini_get_class (method, token, generic_context);
10760                         CHECK_TYPELOAD (klass);
10761
10762                         mono_save_token_info (cfg, image, token, klass);
10763
10764                         context_used = mini_class_check_context_used (cfg, klass);
10765
10766                         if (mini_is_gsharedvt_klass (klass)) {
10767                                 res = handle_unbox_gsharedvt (cfg, klass, *sp);
10768                                 inline_costs += 2;
10769                         } else if (generic_class_is_reference_type (cfg, klass)) {
10770                                 res = handle_castclass (cfg, klass, *sp, ip, &inline_costs);
10771                                 CHECK_CFG_EXCEPTION;
10772                         } else if (mono_class_is_nullable (klass)) {
10773                                 res = handle_unbox_nullable (cfg, *sp, klass, context_used);
10774                         } else {
10775                                 addr = handle_unbox (cfg, klass, sp, context_used);
10776                                 /* LDOBJ */
10777                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10778                                 res = ins;
10779                                 inline_costs += 2;
10780                         }
10781
10782                         *sp ++ = res;
10783                         ip += 5;
10784                         break;
10785                 }
10786                 case CEE_BOX: {
10787                         MonoInst *val;
10788                         MonoClass *enum_class;
10789                         MonoMethod *has_flag;
10790
10791                         CHECK_STACK (1);
10792                         --sp;
10793                         val = *sp;
10794                         CHECK_OPSIZE (5);
10795                         token = read32 (ip + 1);
10796                         klass = mini_get_class (method, token, generic_context);
10797                         CHECK_TYPELOAD (klass);
10798
10799                         mono_save_token_info (cfg, image, token, klass);
10800
10801                         context_used = mini_class_check_context_used (cfg, klass);
10802
10803                         if (generic_class_is_reference_type (cfg, klass)) {
10804                                 *sp++ = val;
10805                                 ip += 5;
10806                                 break;
10807                         }
10808
10809                         if (klass == mono_defaults.void_class)
10810                                 UNVERIFIED;
10811                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
10812                                 UNVERIFIED;
10813                         /* frequent check in generic code: box (struct), brtrue */
10814
10815                         /*
10816                          * Look for:
10817                          *
10818                          *   <push int/long ptr>
10819                          *   <push int/long>
10820                          *   box MyFlags
10821                          *   constrained. MyFlags
10822                          *   callvirt instace bool class [mscorlib] System.Enum::HasFlag (class [mscorlib] System.Enum)
10823                          *
10824                          * If we find this sequence and the operand types on box and constrained
10825                          * are equal, we can emit a specialized instruction sequence instead of
10826                          * the very slow HasFlag () call.
10827                          */
10828                         if ((cfg->opt & MONO_OPT_INTRINS) &&
10829                             /* Cheap checks first. */
10830                             ip + 5 + 6 + 5 < end &&
10831                             ip [5] == CEE_PREFIX1 &&
10832                             ip [6] == CEE_CONSTRAINED_ &&
10833                             ip [11] == CEE_CALLVIRT &&
10834                             ip_in_bb (cfg, cfg->cbb, ip + 5 + 6 + 5) &&
10835                             mono_class_is_enum (klass) &&
10836                             (enum_class = mini_get_class (method, read32 (ip + 7), generic_context)) &&
10837                             (has_flag = mini_get_method (cfg, method, read32 (ip + 12), NULL, generic_context)) &&
10838                             has_flag->klass == mono_defaults.enum_class &&
10839                             !strcmp (has_flag->name, "HasFlag") &&
10840                             has_flag->signature->hasthis &&
10841                             has_flag->signature->param_count == 1) {
10842                                 CHECK_TYPELOAD (enum_class);
10843
10844                                 if (enum_class == klass) {
10845                                         MonoInst *enum_this, *enum_flag;
10846
10847                                         ip += 5 + 6 + 5;
10848                                         --sp;
10849
10850                                         enum_this = sp [0];
10851                                         enum_flag = sp [1];
10852
10853                                         *sp++ = handle_enum_has_flag (cfg, klass, enum_this, enum_flag);
10854                                         break;
10855                                 }
10856                         }
10857
10858                         // FIXME: LLVM can't handle the inconsistent bb linking
10859                         if (!mono_class_is_nullable (klass) &&
10860                                 !mini_is_gsharedvt_klass (klass) &&
10861                                 ip + 5 < end && ip_in_bb (cfg, cfg->cbb, ip + 5) &&
10862                                 (ip [5] == CEE_BRTRUE || 
10863                                  ip [5] == CEE_BRTRUE_S ||
10864                                  ip [5] == CEE_BRFALSE ||
10865                                  ip [5] == CEE_BRFALSE_S)) {
10866                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
10867                                 int dreg;
10868                                 MonoBasicBlock *true_bb, *false_bb;
10869
10870                                 ip += 5;
10871
10872                                 if (cfg->verbose_level > 3) {
10873                                         printf ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
10874                                         printf ("<box+brtrue opt>\n");
10875                                 }
10876
10877                                 switch (*ip) {
10878                                 case CEE_BRTRUE_S:
10879                                 case CEE_BRFALSE_S:
10880                                         CHECK_OPSIZE (2);
10881                                         ip++;
10882                                         target = ip + 1 + (signed char)(*ip);
10883                                         ip++;
10884                                         break;
10885                                 case CEE_BRTRUE:
10886                                 case CEE_BRFALSE:
10887                                         CHECK_OPSIZE (5);
10888                                         ip++;
10889                                         target = ip + 4 + (gint)(read32 (ip));
10890                                         ip += 4;
10891                                         break;
10892                                 default:
10893                                         g_assert_not_reached ();
10894                                 }
10895
10896                                 /* 
10897                                  * We need to link both bblocks, since it is needed for handling stack
10898                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
10899                                  * Branching to only one of them would lead to inconsistencies, so
10900                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
10901                                  */
10902                                 GET_BBLOCK (cfg, true_bb, target);
10903                                 GET_BBLOCK (cfg, false_bb, ip);
10904
10905                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
10906                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
10907
10908                                 if (sp != stack_start) {
10909                                         handle_stack_args (cfg, stack_start, sp - stack_start);
10910                                         sp = stack_start;
10911                                         CHECK_UNVERIFIABLE (cfg);
10912                                 }
10913
10914                                 if (COMPILE_LLVM (cfg)) {
10915                                         dreg = alloc_ireg (cfg);
10916                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
10917                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
10918
10919                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
10920                                 } else {
10921                                         /* The JIT can't eliminate the iconst+compare */
10922                                         MONO_INST_NEW (cfg, ins, OP_BR);
10923                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
10924                                         MONO_ADD_INS (cfg->cbb, ins);
10925                                 }
10926
10927                                 start_new_bblock = 1;
10928                                 break;
10929                         }
10930
10931                         *sp++ = handle_box (cfg, val, klass, context_used);
10932
10933                         CHECK_CFG_EXCEPTION;
10934                         ip += 5;
10935                         inline_costs += 1;
10936                         break;
10937                 }
10938                 case CEE_UNBOX: {
10939                         CHECK_STACK (1);
10940                         --sp;
10941                         CHECK_OPSIZE (5);
10942                         token = read32 (ip + 1);
10943                         klass = mini_get_class (method, token, generic_context);
10944                         CHECK_TYPELOAD (klass);
10945
10946                         mono_save_token_info (cfg, image, token, klass);
10947
10948                         context_used = mini_class_check_context_used (cfg, klass);
10949
10950                         if (mono_class_is_nullable (klass)) {
10951                                 MonoInst *val;
10952
10953                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
10954                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
10955
10956                                 *sp++= ins;
10957                         } else {
10958                                 ins = handle_unbox (cfg, klass, sp, context_used);
10959                                 *sp++ = ins;
10960                         }
10961                         ip += 5;
10962                         inline_costs += 2;
10963                         break;
10964                 }
10965                 case CEE_LDFLD:
10966                 case CEE_LDFLDA:
10967                 case CEE_STFLD:
10968                 case CEE_LDSFLD:
10969                 case CEE_LDSFLDA:
10970                 case CEE_STSFLD: {
10971                         MonoClassField *field;
10972 #ifndef DISABLE_REMOTING
10973                         int costs;
10974 #endif
10975                         guint foffset;
10976                         gboolean is_instance;
10977                         int op;
10978                         gpointer addr = NULL;
10979                         gboolean is_special_static;
10980                         MonoType *ftype;
10981                         MonoInst *store_val = NULL;
10982                         MonoInst *thread_ins;
10983
10984                         op = *ip;
10985                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
10986                         if (is_instance) {
10987                                 if (op == CEE_STFLD) {
10988                                         CHECK_STACK (2);
10989                                         sp -= 2;
10990                                         store_val = sp [1];
10991                                 } else {
10992                                         CHECK_STACK (1);
10993                                         --sp;
10994                                 }
10995                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
10996                                         UNVERIFIED;
10997                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
10998                                         UNVERIFIED;
10999                         } else {
11000                                 if (op == CEE_STSFLD) {
11001                                         CHECK_STACK (1);
11002                                         sp--;
11003                                         store_val = sp [0];
11004                                 }
11005                         }
11006
11007                         CHECK_OPSIZE (5);
11008                         token = read32 (ip + 1);
11009                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
11010                                 field = (MonoClassField *)mono_method_get_wrapper_data (method, token);
11011                                 klass = field->parent;
11012                         }
11013                         else {
11014                                 field = mono_field_from_token_checked (image, token, &klass, generic_context, &cfg->error);
11015                                 CHECK_CFG_ERROR;
11016                         }
11017                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
11018                                 FIELD_ACCESS_FAILURE (method, field);
11019                         mono_class_init (klass);
11020
11021                         /* if the class is Critical then transparent code cannot access it's fields */
11022                         if (!is_instance && mono_security_core_clr_enabled ())
11023                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11024
11025                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
11026                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
11027                         if (mono_security_core_clr_enabled ())
11028                                 ensure_method_is_allowed_to_access_field (cfg, method, field);
11029                         */
11030
11031                         ftype = mono_field_get_type (field);
11032
11033                         /*
11034                          * LDFLD etc. is usable on static fields as well, so convert those cases to
11035                          * the static case.
11036                          */
11037                         if (is_instance && ftype->attrs & FIELD_ATTRIBUTE_STATIC) {
11038                                 switch (op) {
11039                                 case CEE_LDFLD:
11040                                         op = CEE_LDSFLD;
11041                                         break;
11042                                 case CEE_STFLD:
11043                                         op = CEE_STSFLD;
11044                                         break;
11045                                 case CEE_LDFLDA:
11046                                         op = CEE_LDSFLDA;
11047                                         break;
11048                                 default:
11049                                         g_assert_not_reached ();
11050                                 }
11051                                 is_instance = FALSE;
11052                         }
11053
11054                         context_used = mini_class_check_context_used (cfg, klass);
11055
11056                         /* INSTANCE CASE */
11057
11058                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
11059                         if (op == CEE_STFLD) {
11060                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
11061                                         UNVERIFIED;
11062 #ifndef DISABLE_REMOTING
11063                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
11064                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
11065                                         MonoInst *iargs [5];
11066
11067                                         GSHAREDVT_FAILURE (op);
11068
11069                                         iargs [0] = sp [0];
11070                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11071                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11072                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
11073                                                     field->offset);
11074                                         iargs [4] = sp [1];
11075
11076                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11077                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
11078                                                                                            iargs, ip, cfg->real_offset, TRUE);
11079                                                 CHECK_CFG_EXCEPTION;
11080                                                 g_assert (costs > 0);
11081                                                       
11082                                                 cfg->real_offset += 5;
11083
11084                                                 inline_costs += costs;
11085                                         } else {
11086                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
11087                                         }
11088                                 } else
11089 #endif
11090                                 {
11091                                         MonoInst *store;
11092
11093                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11094
11095                                         if (mini_is_gsharedvt_klass (klass)) {
11096                                                 MonoInst *offset_ins;
11097
11098                                                 context_used = mini_class_check_context_used (cfg, klass);
11099
11100                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11101                                                 /* The value is offset by 1 */
11102                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11103                                                 dreg = alloc_ireg_mp (cfg);
11104                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11105                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
11106                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
11107                                         } else {
11108                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
11109                                         }
11110                                         if (sp [0]->opcode != OP_LDADDR)
11111                                                 store->flags |= MONO_INST_FAULT;
11112
11113                                 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)) {
11114                                         /* insert call to write barrier */
11115                                         MonoInst *ptr;
11116                                         int dreg;
11117
11118                                         dreg = alloc_ireg_mp (cfg);
11119                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11120                                         emit_write_barrier (cfg, ptr, sp [1]);
11121                                 }
11122
11123                                         store->flags |= ins_flag;
11124                                 }
11125                                 ins_flag = 0;
11126                                 ip += 5;
11127                                 break;
11128                         }
11129
11130 #ifndef DISABLE_REMOTING
11131                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
11132                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
11133                                 MonoInst *iargs [4];
11134
11135                                 GSHAREDVT_FAILURE (op);
11136
11137                                 iargs [0] = sp [0];
11138                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11139                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
11140                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
11141                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
11142                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
11143                                                                                    iargs, ip, cfg->real_offset, TRUE);
11144                                         CHECK_CFG_EXCEPTION;
11145                                         g_assert (costs > 0);
11146                                                       
11147                                         cfg->real_offset += 5;
11148
11149                                         *sp++ = iargs [0];
11150
11151                                         inline_costs += costs;
11152                                 } else {
11153                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
11154                                         *sp++ = ins;
11155                                 }
11156                         } else 
11157 #endif
11158                         if (is_instance) {
11159                                 if (sp [0]->type == STACK_VTYPE) {
11160                                         MonoInst *var;
11161
11162                                         /* Have to compute the address of the variable */
11163
11164                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
11165                                         if (!var)
11166                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
11167                                         else
11168                                                 g_assert (var->klass == klass);
11169                                         
11170                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
11171                                         sp [0] = ins;
11172                                 }
11173
11174                                 if (op == CEE_LDFLDA) {
11175                                         if (sp [0]->type == STACK_OBJ) {
11176                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
11177                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
11178                                         }
11179
11180                                         dreg = alloc_ireg_mp (cfg);
11181
11182                                         if (mini_is_gsharedvt_klass (klass)) {
11183                                                 MonoInst *offset_ins;
11184
11185                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11186                                                 /* The value is offset by 1 */
11187                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11188                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11189                                         } else {
11190                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
11191                                         }
11192                                         ins->klass = mono_class_from_mono_type (field->type);
11193                                         ins->type = STACK_MP;
11194                                         *sp++ = ins;
11195                                 } else {
11196                                         MonoInst *load;
11197
11198                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
11199
11200                                         if (mini_is_gsharedvt_klass (klass)) {
11201                                                 MonoInst *offset_ins;
11202
11203                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11204                                                 /* The value is offset by 1 */
11205                                                 EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11206                                                 dreg = alloc_ireg_mp (cfg);
11207                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
11208                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
11209                                         } else {
11210                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
11211                                         }
11212                                         load->flags |= ins_flag;
11213                                         if (sp [0]->opcode != OP_LDADDR)
11214                                                 load->flags |= MONO_INST_FAULT;
11215                                         *sp++ = load;
11216                                 }
11217                         }
11218
11219                         if (is_instance) {
11220                                 ins_flag = 0;
11221                                 ip += 5;
11222                                 break;
11223                         }
11224
11225                         /* STATIC CASE */
11226                         context_used = mini_class_check_context_used (cfg, klass);
11227
11228                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
11229                                 UNVERIFIED;
11230
11231                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
11232                          * to be called here.
11233                          */
11234                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
11235                                 mono_class_vtable (cfg->domain, klass);
11236                                 CHECK_TYPELOAD (klass);
11237                         }
11238                         mono_domain_lock (cfg->domain);
11239                         if (cfg->domain->special_static_fields)
11240                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
11241                         mono_domain_unlock (cfg->domain);
11242
11243                         is_special_static = mono_class_field_is_special_static (field);
11244
11245                         if (is_special_static && ((gsize)addr & 0x80000000) == 0)
11246                                 thread_ins = mono_get_thread_intrinsic (cfg);
11247                         else
11248                                 thread_ins = NULL;
11249
11250                         /* Generate IR to compute the field address */
11251                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && thread_ins && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
11252                                 /*
11253                                  * Fast access to TLS data
11254                                  * Inline version of get_thread_static_data () in
11255                                  * threads.c.
11256                                  */
11257                                 guint32 offset;
11258                                 int idx, static_data_reg, array_reg, dreg;
11259
11260                                 GSHAREDVT_FAILURE (op);
11261
11262                                 MONO_ADD_INS (cfg->cbb, thread_ins);
11263                                 static_data_reg = alloc_ireg (cfg);
11264                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, MONO_STRUCT_OFFSET (MonoInternalThread, static_data));
11265
11266                                 if (cfg->compile_aot) {
11267                                         int offset_reg, offset2_reg, idx_reg;
11268
11269                                         /* For TLS variables, this will return the TLS offset */
11270                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
11271                                         offset_reg = ins->dreg;
11272                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
11273                                         idx_reg = alloc_ireg (cfg);
11274                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, idx_reg, offset_reg, 0x3f);
11275                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
11276                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
11277                                         array_reg = alloc_ireg (cfg);
11278                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
11279                                         offset2_reg = alloc_ireg (cfg);
11280                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_UN_IMM, offset2_reg, offset_reg, 6);
11281                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset2_reg, 0x1ffffff);
11282                                         dreg = alloc_ireg (cfg);
11283                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
11284                                 } else {
11285                                         offset = (gsize)addr & 0x7fffffff;
11286                                         idx = offset & 0x3f;
11287
11288                                         array_reg = alloc_ireg (cfg);
11289                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
11290                                         dreg = alloc_ireg (cfg);
11291                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, ((offset >> 6) & 0x1ffffff));
11292                                 }
11293                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
11294                                         (cfg->compile_aot && is_special_static) ||
11295                                         (context_used && is_special_static)) {
11296                                 MonoInst *iargs [2];
11297
11298                                 g_assert (field->parent);
11299                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11300                                 if (context_used) {
11301                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
11302                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
11303                                 } else {
11304                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11305                                 }
11306                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11307                         } else if (context_used) {
11308                                 MonoInst *static_data;
11309
11310                                 /*
11311                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
11312                                         method->klass->name_space, method->klass->name, method->name,
11313                                         depth, field->offset);
11314                                 */
11315
11316                                 if (mono_class_needs_cctor_run (klass, method))
11317                                         emit_class_init (cfg, klass);
11318
11319                                 /*
11320                                  * The pointer we're computing here is
11321                                  *
11322                                  *   super_info.static_data + field->offset
11323                                  */
11324                                 static_data = emit_get_rgctx_klass (cfg, context_used,
11325                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
11326
11327                                 if (mini_is_gsharedvt_klass (klass)) {
11328                                         MonoInst *offset_ins;
11329
11330                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
11331                                         /* The value is offset by 1 */
11332                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PSUB_IMM, offset_ins->dreg, offset_ins->dreg, 1);
11333                                         dreg = alloc_ireg_mp (cfg);
11334                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
11335                                 } else if (field->offset == 0) {
11336                                         ins = static_data;
11337                                 } else {
11338                                         int addr_reg = mono_alloc_preg (cfg);
11339                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
11340                                 }
11341                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
11342                                 MonoInst *iargs [2];
11343
11344                                 g_assert (field->parent);
11345                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11346                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
11347                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
11348                         } else {
11349                                 MonoVTable *vtable = NULL;
11350
11351                                 if (!cfg->compile_aot)
11352                                         vtable = mono_class_vtable (cfg->domain, klass);
11353                                 CHECK_TYPELOAD (klass);
11354
11355                                 if (!addr) {
11356                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
11357                                                 if (!(g_slist_find (class_inits, klass))) {
11358                                                         emit_class_init (cfg, klass);
11359                                                         if (cfg->verbose_level > 2)
11360                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
11361                                                         class_inits = g_slist_prepend (class_inits, klass);
11362                                                 }
11363                                         } else {
11364                                                 if (cfg->run_cctors) {
11365                                                         MonoException *ex;
11366                                                         /* This makes so that inline cannot trigger */
11367                                                         /* .cctors: too many apps depend on them */
11368                                                         /* running with a specific order... */
11369                                                         g_assert (vtable);
11370                                                         if (! vtable->initialized)
11371                                                                 INLINE_FAILURE ("class init");
11372                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
11373                                                         if (ex) {
11374                                                                 set_exception_object (cfg, ex);
11375                                                                 goto exception_exit;
11376                                                         }
11377                                                 }
11378                                         }
11379                                         if (cfg->compile_aot)
11380                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
11381                                         else {
11382                                                 g_assert (vtable);
11383                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11384                                                 g_assert (addr);
11385                                                 EMIT_NEW_PCONST (cfg, ins, addr);
11386                                         }
11387                                 } else {
11388                                         MonoInst *iargs [1];
11389                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
11390                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
11391                                 }
11392                         }
11393
11394                         /* Generate IR to do the actual load/store operation */
11395
11396                         if ((op == CEE_STFLD || op == CEE_STSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11397                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11398                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11399                         }
11400
11401                         if (op == CEE_LDSFLDA) {
11402                                 ins->klass = mono_class_from_mono_type (ftype);
11403                                 ins->type = STACK_PTR;
11404                                 *sp++ = ins;
11405                         } else if (op == CEE_STSFLD) {
11406                                 MonoInst *store;
11407
11408                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
11409                                 store->flags |= ins_flag;
11410                         } else {
11411                                 gboolean is_const = FALSE;
11412                                 MonoVTable *vtable = NULL;
11413                                 gpointer addr = NULL;
11414
11415                                 if (!context_used) {
11416                                         vtable = mono_class_vtable (cfg->domain, klass);
11417                                         CHECK_TYPELOAD (klass);
11418                                 }
11419                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
11420                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
11421                                         int ro_type = ftype->type;
11422                                         if (!addr)
11423                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
11424                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
11425                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
11426                                         }
11427
11428                                         GSHAREDVT_FAILURE (op);
11429
11430                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
11431                                         is_const = TRUE;
11432                                         switch (ro_type) {
11433                                         case MONO_TYPE_BOOLEAN:
11434                                         case MONO_TYPE_U1:
11435                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
11436                                                 sp++;
11437                                                 break;
11438                                         case MONO_TYPE_I1:
11439                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
11440                                                 sp++;
11441                                                 break;                                          
11442                                         case MONO_TYPE_CHAR:
11443                                         case MONO_TYPE_U2:
11444                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
11445                                                 sp++;
11446                                                 break;
11447                                         case MONO_TYPE_I2:
11448                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
11449                                                 sp++;
11450                                                 break;
11451                                                 break;
11452                                         case MONO_TYPE_I4:
11453                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
11454                                                 sp++;
11455                                                 break;                                          
11456                                         case MONO_TYPE_U4:
11457                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
11458                                                 sp++;
11459                                                 break;
11460                                         case MONO_TYPE_I:
11461                                         case MONO_TYPE_U:
11462                                         case MONO_TYPE_PTR:
11463                                         case MONO_TYPE_FNPTR:
11464                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11465                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
11466                                                 sp++;
11467                                                 break;
11468                                         case MONO_TYPE_STRING:
11469                                         case MONO_TYPE_OBJECT:
11470                                         case MONO_TYPE_CLASS:
11471                                         case MONO_TYPE_SZARRAY:
11472                                         case MONO_TYPE_ARRAY:
11473                                                 if (!mono_gc_is_moving ()) {
11474                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
11475                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
11476                                                         sp++;
11477                                                 } else {
11478                                                         is_const = FALSE;
11479                                                 }
11480                                                 break;
11481                                         case MONO_TYPE_I8:
11482                                         case MONO_TYPE_U8:
11483                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
11484                                                 sp++;
11485                                                 break;
11486                                         case MONO_TYPE_R4:
11487                                         case MONO_TYPE_R8:
11488                                         case MONO_TYPE_VALUETYPE:
11489                                         default:
11490                                                 is_const = FALSE;
11491                                                 break;
11492                                         }
11493                                 }
11494
11495                                 if (!is_const) {
11496                                         MonoInst *load;
11497
11498                                         CHECK_STACK_OVF (1);
11499
11500                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
11501                                         load->flags |= ins_flag;
11502                                         ins_flag = 0;
11503                                         *sp++ = load;
11504                                 }
11505                         }
11506
11507                         if ((op == CEE_LDFLD || op == CEE_LDSFLD) && (ins_flag & MONO_INST_VOLATILE)) {
11508                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
11509                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_ACQ);
11510                         }
11511
11512                         ins_flag = 0;
11513                         ip += 5;
11514                         break;
11515                 }
11516                 case CEE_STOBJ:
11517                         CHECK_STACK (2);
11518                         sp -= 2;
11519                         CHECK_OPSIZE (5);
11520                         token = read32 (ip + 1);
11521                         klass = mini_get_class (method, token, generic_context);
11522                         CHECK_TYPELOAD (klass);
11523                         if (ins_flag & MONO_INST_VOLATILE) {
11524                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
11525                                 emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
11526                         }
11527                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
11528                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
11529                         ins->flags |= ins_flag;
11530                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
11531                                         generic_class_is_reference_type (cfg, klass)) {
11532                                 /* insert call to write barrier */
11533                                 emit_write_barrier (cfg, sp [0], sp [1]);
11534                         }
11535                         ins_flag = 0;
11536                         ip += 5;
11537                         inline_costs += 1;
11538                         break;
11539
11540                         /*
11541                          * Array opcodes
11542                          */
11543                 case CEE_NEWARR: {
11544                         MonoInst *len_ins;
11545                         const char *data_ptr;
11546                         int data_size = 0;
11547                         guint32 field_token;
11548
11549                         CHECK_STACK (1);
11550                         --sp;
11551
11552                         CHECK_OPSIZE (5);
11553                         token = read32 (ip + 1);
11554
11555                         klass = mini_get_class (method, token, generic_context);
11556                         CHECK_TYPELOAD (klass);
11557
11558                         context_used = mini_class_check_context_used (cfg, klass);
11559
11560                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
11561                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
11562                                 ins->sreg1 = sp [0]->dreg;
11563                                 ins->type = STACK_I4;
11564                                 ins->dreg = alloc_ireg (cfg);
11565                                 MONO_ADD_INS (cfg->cbb, ins);
11566                                 *sp = mono_decompose_opcode (cfg, ins);
11567                         }
11568
11569                         if (context_used) {
11570                                 MonoInst *args [3];
11571                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11572                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
11573
11574                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
11575
11576                                 /* vtable */
11577                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
11578                                         array_class, MONO_RGCTX_INFO_VTABLE);
11579                                 /* array len */
11580                                 args [1] = sp [0];
11581
11582                                 if (managed_alloc)
11583                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
11584                                 else
11585                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
11586                         } else {
11587                                 if (cfg->opt & MONO_OPT_SHARED) {
11588                                         /* Decompose now to avoid problems with references to the domainvar */
11589                                         MonoInst *iargs [3];
11590
11591                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
11592                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
11593                                         iargs [2] = sp [0];
11594
11595                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
11596                                 } else {
11597                                         /* Decompose later since it is needed by abcrem */
11598                                         MonoClass *array_type = mono_array_class_get (klass, 1);
11599                                         mono_class_vtable (cfg->domain, array_type);
11600                                         CHECK_TYPELOAD (array_type);
11601
11602                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
11603                                         ins->dreg = alloc_ireg_ref (cfg);
11604                                         ins->sreg1 = sp [0]->dreg;
11605                                         ins->inst_newa_class = klass;
11606                                         ins->type = STACK_OBJ;
11607                                         ins->klass = array_type;
11608                                         MONO_ADD_INS (cfg->cbb, ins);
11609                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11610                                         cfg->cbb->has_array_access = TRUE;
11611
11612                                         /* Needed so mono_emit_load_get_addr () gets called */
11613                                         mono_get_got_var (cfg);
11614                                 }
11615                         }
11616
11617                         len_ins = sp [0];
11618                         ip += 5;
11619                         *sp++ = ins;
11620                         inline_costs += 1;
11621
11622                         /* 
11623                          * we inline/optimize the initialization sequence if possible.
11624                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
11625                          * for small sizes open code the memcpy
11626                          * ensure the rva field is big enough
11627                          */
11628                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, cfg->cbb, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size, &field_token))) {
11629                                 MonoMethod *memcpy_method = get_memcpy_method ();
11630                                 MonoInst *iargs [3];
11631                                 int add_reg = alloc_ireg_mp (cfg);
11632
11633                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, MONO_STRUCT_OFFSET (MonoArray, vector));
11634                                 if (cfg->compile_aot) {
11635                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
11636                                 } else {
11637                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
11638                                 }
11639                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
11640                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11641                                 ip += 11;
11642                         }
11643
11644                         break;
11645                 }
11646                 case CEE_LDLEN:
11647                         CHECK_STACK (1);
11648                         --sp;
11649                         if (sp [0]->type != STACK_OBJ)
11650                                 UNVERIFIED;
11651
11652                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
11653                         ins->dreg = alloc_preg (cfg);
11654                         ins->sreg1 = sp [0]->dreg;
11655                         ins->type = STACK_I4;
11656                         /* This flag will be inherited by the decomposition */
11657                         ins->flags |= MONO_INST_FAULT;
11658                         MONO_ADD_INS (cfg->cbb, ins);
11659                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
11660                         cfg->cbb->has_array_access = TRUE;
11661                         ip ++;
11662                         *sp++ = ins;
11663                         break;
11664                 case CEE_LDELEMA:
11665                         CHECK_STACK (2);
11666                         sp -= 2;
11667                         CHECK_OPSIZE (5);
11668                         if (sp [0]->type != STACK_OBJ)
11669                                 UNVERIFIED;
11670
11671                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11672
11673                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11674                         CHECK_TYPELOAD (klass);
11675                         /* we need to make sure that this array is exactly the type it needs
11676                          * to be for correctness. the wrappers are lax with their usage
11677                          * so we need to ignore them here
11678                          */
11679                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
11680                                 MonoClass *array_class = mono_array_class_get (klass, 1);
11681                                 mini_emit_check_array_type (cfg, sp [0], array_class);
11682                                 CHECK_TYPELOAD (array_class);
11683                         }
11684
11685                         readonly = FALSE;
11686                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11687                         *sp++ = ins;
11688                         ip += 5;
11689                         break;
11690                 case CEE_LDELEM:
11691                 case CEE_LDELEM_I1:
11692                 case CEE_LDELEM_U1:
11693                 case CEE_LDELEM_I2:
11694                 case CEE_LDELEM_U2:
11695                 case CEE_LDELEM_I4:
11696                 case CEE_LDELEM_U4:
11697                 case CEE_LDELEM_I8:
11698                 case CEE_LDELEM_I:
11699                 case CEE_LDELEM_R4:
11700                 case CEE_LDELEM_R8:
11701                 case CEE_LDELEM_REF: {
11702                         MonoInst *addr;
11703
11704                         CHECK_STACK (2);
11705                         sp -= 2;
11706
11707                         if (*ip == CEE_LDELEM) {
11708                                 CHECK_OPSIZE (5);
11709                                 token = read32 (ip + 1);
11710                                 klass = mini_get_class (method, token, generic_context);
11711                                 CHECK_TYPELOAD (klass);
11712                                 mono_class_init (klass);
11713                         }
11714                         else
11715                                 klass = array_access_to_klass (*ip);
11716
11717                         if (sp [0]->type != STACK_OBJ)
11718                                 UNVERIFIED;
11719
11720                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11721
11722                         if (mini_is_gsharedvt_variable_klass (klass)) {
11723                                 // FIXME-VT: OP_ICONST optimization
11724                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11725                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11726                                 ins->opcode = OP_LOADV_MEMBASE;
11727                         } else if (sp [1]->opcode == OP_ICONST) {
11728                                 int array_reg = sp [0]->dreg;
11729                                 int index_reg = sp [1]->dreg;
11730                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + MONO_STRUCT_OFFSET (MonoArray, vector);
11731
11732                                 if (SIZEOF_REGISTER == 8 && COMPILE_LLVM (cfg))
11733                                         MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, index_reg, index_reg);
11734
11735                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
11736                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
11737                         } else {
11738                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
11739                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
11740                         }
11741                         *sp++ = ins;
11742                         if (*ip == CEE_LDELEM)
11743                                 ip += 5;
11744                         else
11745                                 ++ip;
11746                         break;
11747                 }
11748                 case CEE_STELEM_I:
11749                 case CEE_STELEM_I1:
11750                 case CEE_STELEM_I2:
11751                 case CEE_STELEM_I4:
11752                 case CEE_STELEM_I8:
11753                 case CEE_STELEM_R4:
11754                 case CEE_STELEM_R8:
11755                 case CEE_STELEM_REF:
11756                 case CEE_STELEM: {
11757                         CHECK_STACK (3);
11758                         sp -= 3;
11759
11760                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
11761
11762                         if (*ip == CEE_STELEM) {
11763                                 CHECK_OPSIZE (5);
11764                                 token = read32 (ip + 1);
11765                                 klass = mini_get_class (method, token, generic_context);
11766                                 CHECK_TYPELOAD (klass);
11767                                 mono_class_init (klass);
11768                         }
11769                         else
11770                                 klass = array_access_to_klass (*ip);
11771
11772                         if (sp [0]->type != STACK_OBJ)
11773                                 UNVERIFIED;
11774
11775                         emit_array_store (cfg, klass, sp, TRUE);
11776
11777                         if (*ip == CEE_STELEM)
11778                                 ip += 5;
11779                         else
11780                                 ++ip;
11781                         inline_costs += 1;
11782                         break;
11783                 }
11784                 case CEE_CKFINITE: {
11785                         CHECK_STACK (1);
11786                         --sp;
11787
11788                         if (cfg->llvm_only) {
11789                                 MonoInst *iargs [1];
11790
11791                                 iargs [0] = sp [0];
11792                                 *sp++ = mono_emit_jit_icall (cfg, mono_ckfinite, iargs);
11793                         } else  {
11794                                 MONO_INST_NEW (cfg, ins, OP_CKFINITE);
11795                                 ins->sreg1 = sp [0]->dreg;
11796                                 ins->dreg = alloc_freg (cfg);
11797                                 ins->type = STACK_R8;
11798                                 MONO_ADD_INS (cfg->cbb, ins);
11799
11800                                 *sp++ = mono_decompose_opcode (cfg, ins);
11801                         }
11802
11803                         ++ip;
11804                         break;
11805                 }
11806                 case CEE_REFANYVAL: {
11807                         MonoInst *src_var, *src;
11808
11809                         int klass_reg = alloc_preg (cfg);
11810                         int dreg = alloc_preg (cfg);
11811
11812                         GSHAREDVT_FAILURE (*ip);
11813
11814                         CHECK_STACK (1);
11815                         MONO_INST_NEW (cfg, ins, *ip);
11816                         --sp;
11817                         CHECK_OPSIZE (5);
11818                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11819                         CHECK_TYPELOAD (klass);
11820
11821                         context_used = mini_class_check_context_used (cfg, klass);
11822
11823                         // FIXME:
11824                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11825                         if (!src_var)
11826                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11827                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11828                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass));
11829
11830                         if (context_used) {
11831                                 MonoInst *klass_ins;
11832
11833                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
11834                                                 klass, MONO_RGCTX_INFO_KLASS);
11835
11836                                 // FIXME:
11837                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
11838                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
11839                         } else {
11840                                 mini_emit_class_check (cfg, klass_reg, klass);
11841                         }
11842                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value));
11843                         ins->type = STACK_MP;
11844                         ins->klass = klass;
11845                         *sp++ = ins;
11846                         ip += 5;
11847                         break;
11848                 }
11849                 case CEE_MKREFANY: {
11850                         MonoInst *loc, *addr;
11851
11852                         GSHAREDVT_FAILURE (*ip);
11853
11854                         CHECK_STACK (1);
11855                         MONO_INST_NEW (cfg, ins, *ip);
11856                         --sp;
11857                         CHECK_OPSIZE (5);
11858                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
11859                         CHECK_TYPELOAD (klass);
11860
11861                         context_used = mini_class_check_context_used (cfg, klass);
11862
11863                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
11864                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
11865
11866                         if (context_used) {
11867                                 MonoInst *const_ins;
11868                                 int type_reg = alloc_preg (cfg);
11869
11870                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
11871                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
11872                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11873                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11874                         } else if (cfg->compile_aot) {
11875                                 int const_reg = alloc_preg (cfg);
11876                                 int type_reg = alloc_preg (cfg);
11877
11878                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
11879                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
11880                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, MONO_STRUCT_OFFSET (MonoClass, byval_arg));
11881                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
11882                         } else {
11883                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
11884                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, klass), klass);
11885                         }
11886                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
11887
11888                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
11889                         ins->type = STACK_VTYPE;
11890                         ins->klass = mono_defaults.typed_reference_class;
11891                         *sp++ = ins;
11892                         ip += 5;
11893                         break;
11894                 }
11895                 case CEE_LDTOKEN: {
11896                         gpointer handle;
11897                         MonoClass *handle_class;
11898
11899                         CHECK_STACK_OVF (1);
11900
11901                         CHECK_OPSIZE (5);
11902                         n = read32 (ip + 1);
11903
11904                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
11905                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
11906                                 handle = mono_method_get_wrapper_data (method, n);
11907                                 handle_class = (MonoClass *)mono_method_get_wrapper_data (method, n + 1);
11908                                 if (handle_class == mono_defaults.typehandle_class)
11909                                         handle = &((MonoClass*)handle)->byval_arg;
11910                         }
11911                         else {
11912                                 handle = mono_ldtoken_checked (image, n, &handle_class, generic_context, &cfg->error);
11913                                 CHECK_CFG_ERROR;
11914                         }
11915                         if (!handle)
11916                                 LOAD_ERROR;
11917                         mono_class_init (handle_class);
11918                         if (cfg->gshared) {
11919                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
11920                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
11921                                         /* This case handles ldtoken
11922                                            of an open type, like for
11923                                            typeof(Gen<>). */
11924                                         context_used = 0;
11925                                 } else if (handle_class == mono_defaults.typehandle_class) {
11926                                         context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type ((MonoType *)handle));
11927                                 } else if (handle_class == mono_defaults.fieldhandle_class)
11928                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
11929                                 else if (handle_class == mono_defaults.methodhandle_class)
11930                                         context_used = mini_method_check_context_used (cfg, (MonoMethod *)handle);
11931                                 else
11932                                         g_assert_not_reached ();
11933                         }
11934
11935                         if ((cfg->opt & MONO_OPT_SHARED) &&
11936                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
11937                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
11938                                 MonoInst *addr, *vtvar, *iargs [3];
11939                                 int method_context_used;
11940
11941                                 method_context_used = mini_method_check_context_used (cfg, method);
11942
11943                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
11944
11945                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
11946                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
11947                                 if (method_context_used) {
11948                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
11949                                                 method, MONO_RGCTX_INFO_METHOD);
11950                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
11951                                 } else {
11952                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
11953                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
11954                                 }
11955                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11956
11957                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
11958
11959                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11960                         } else {
11961                                 if ((ip + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 5) && 
11962                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
11963                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
11964                                         (cmethod->klass == mono_defaults.systemtype_class) &&
11965                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
11966                                         MonoClass *tclass = mono_class_from_mono_type ((MonoType *)handle);
11967
11968                                         mono_class_init (tclass);
11969                                         if (context_used) {
11970                                                 ins = emit_get_rgctx_klass (cfg, context_used,
11971                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
11972                                         } else if (cfg->compile_aot) {
11973                                                 if (method->wrapper_type) {
11974                                                         mono_error_init (&error); //got to do it since there are multiple conditionals below
11975                                                         if (mono_class_get_checked (tclass->image, tclass->type_token, &error) == tclass && !generic_context) {
11976                                                                 /* Special case for static synchronized wrappers */
11977                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
11978                                                         } else {
11979                                                                 mono_error_cleanup (&error); /* FIXME don't swallow the error */
11980                                                                 /* FIXME: n is not a normal token */
11981                                                                 DISABLE_AOT (cfg);
11982                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11983                                                         }
11984                                                 } else {
11985                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
11986                                                 }
11987                                         } else {
11988                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, (MonoType *)handle));
11989                                         }
11990                                         ins->type = STACK_OBJ;
11991                                         ins->klass = cmethod->klass;
11992                                         ip += 5;
11993                                 } else {
11994                                         MonoInst *addr, *vtvar;
11995
11996                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
11997
11998                                         if (context_used) {
11999                                                 if (handle_class == mono_defaults.typehandle_class) {
12000                                                         ins = emit_get_rgctx_klass (cfg, context_used,
12001                                                                         mono_class_from_mono_type ((MonoType *)handle),
12002                                                                         MONO_RGCTX_INFO_TYPE);
12003                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
12004                                                         ins = emit_get_rgctx_method (cfg, context_used,
12005                                                                         (MonoMethod *)handle, MONO_RGCTX_INFO_METHOD);
12006                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
12007                                                         ins = emit_get_rgctx_field (cfg, context_used,
12008                                                                         (MonoClassField *)handle, MONO_RGCTX_INFO_CLASS_FIELD);
12009                                                 } else {
12010                                                         g_assert_not_reached ();
12011                                                 }
12012                                         } else if (cfg->compile_aot) {
12013                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
12014                                         } else {
12015                                                 EMIT_NEW_PCONST (cfg, ins, handle);
12016                                         }
12017                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12018                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
12019                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12020                                 }
12021                         }
12022
12023                         *sp++ = ins;
12024                         ip += 5;
12025                         break;
12026                 }
12027                 case CEE_THROW:
12028                         CHECK_STACK (1);
12029                         MONO_INST_NEW (cfg, ins, OP_THROW);
12030                         --sp;
12031                         ins->sreg1 = sp [0]->dreg;
12032                         ip++;
12033                         cfg->cbb->out_of_line = TRUE;
12034                         MONO_ADD_INS (cfg->cbb, ins);
12035                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
12036                         MONO_ADD_INS (cfg->cbb, ins);
12037                         sp = stack_start;
12038                         
12039                         link_bblock (cfg, cfg->cbb, end_bblock);
12040                         start_new_bblock = 1;
12041                         /* This can complicate code generation for llvm since the return value might not be defined */
12042                         if (COMPILE_LLVM (cfg))
12043                                 INLINE_FAILURE ("throw");
12044                         break;
12045                 case CEE_ENDFINALLY:
12046                         /* mono_save_seq_point_info () depends on this */
12047                         if (sp != stack_start)
12048                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
12049                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
12050                         MONO_ADD_INS (cfg->cbb, ins);
12051                         ip++;
12052                         start_new_bblock = 1;
12053
12054                         /*
12055                          * Control will leave the method so empty the stack, otherwise
12056                          * the next basic block will start with a nonempty stack.
12057                          */
12058                         while (sp != stack_start) {
12059                                 sp--;
12060                         }
12061                         break;
12062                 case CEE_LEAVE:
12063                 case CEE_LEAVE_S: {
12064                         GList *handlers;
12065
12066                         if (*ip == CEE_LEAVE) {
12067                                 CHECK_OPSIZE (5);
12068                                 target = ip + 5 + (gint32)read32(ip + 1);
12069                         } else {
12070                                 CHECK_OPSIZE (2);
12071                                 target = ip + 2 + (signed char)(ip [1]);
12072                         }
12073
12074                         /* empty the stack */
12075                         while (sp != stack_start) {
12076                                 sp--;
12077                         }
12078
12079                         /* 
12080                          * If this leave statement is in a catch block, check for a
12081                          * pending exception, and rethrow it if necessary.
12082                          * We avoid doing this in runtime invoke wrappers, since those are called
12083                          * by native code which excepts the wrapper to catch all exceptions.
12084                          */
12085                         for (i = 0; i < header->num_clauses; ++i) {
12086                                 MonoExceptionClause *clause = &header->clauses [i];
12087
12088                                 /* 
12089                                  * Use <= in the final comparison to handle clauses with multiple
12090                                  * leave statements, like in bug #78024.
12091                                  * The ordering of the exception clauses guarantees that we find the
12092                                  * innermost clause.
12093                                  */
12094                                 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) {
12095                                         MonoInst *exc_ins;
12096                                         MonoBasicBlock *dont_throw;
12097
12098                                         /*
12099                                           MonoInst *load;
12100
12101                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
12102                                         */
12103
12104                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
12105
12106                                         NEW_BBLOCK (cfg, dont_throw);
12107
12108                                         /*
12109                                          * Currently, we always rethrow the abort exception, despite the 
12110                                          * fact that this is not correct. See thread6.cs for an example. 
12111                                          * But propagating the abort exception is more important than 
12112                                          * getting the sematics right.
12113                                          */
12114                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
12115                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
12116                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
12117
12118                                         MONO_START_BB (cfg, dont_throw);
12119                                 }
12120                         }
12121
12122 #ifdef ENABLE_LLVM
12123                         cfg->cbb->try_end = (intptr_t)(ip - header->code);
12124 #endif
12125
12126                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
12127                                 GList *tmp;
12128                                 MonoExceptionClause *clause;
12129
12130                                 for (tmp = handlers; tmp; tmp = tmp->next) {
12131                                         clause = (MonoExceptionClause *)tmp->data;
12132                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
12133                                         g_assert (tblock);
12134                                         link_bblock (cfg, cfg->cbb, tblock);
12135                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
12136                                         ins->inst_target_bb = tblock;
12137                                         ins->inst_eh_block = clause;
12138                                         MONO_ADD_INS (cfg->cbb, ins);
12139                                         cfg->cbb->has_call_handler = 1;
12140                                         if (COMPILE_LLVM (cfg)) {
12141                                                 MonoBasicBlock *target_bb;
12142
12143                                                 /* 
12144                                                  * Link the finally bblock with the target, since it will
12145                                                  * conceptually branch there.
12146                                                  * FIXME: Have to link the bblock containing the endfinally.
12147                                                  */
12148                                                 GET_BBLOCK (cfg, target_bb, target);
12149                                                 link_bblock (cfg, tblock, target_bb);
12150                                         }
12151                                 }
12152                                 g_list_free (handlers);
12153                         } 
12154
12155                         MONO_INST_NEW (cfg, ins, OP_BR);
12156                         MONO_ADD_INS (cfg->cbb, ins);
12157                         GET_BBLOCK (cfg, tblock, target);
12158                         link_bblock (cfg, cfg->cbb, tblock);
12159                         ins->inst_target_bb = tblock;
12160
12161                         start_new_bblock = 1;
12162
12163                         if (*ip == CEE_LEAVE)
12164                                 ip += 5;
12165                         else
12166                                 ip += 2;
12167
12168                         break;
12169                 }
12170
12171                         /*
12172                          * Mono specific opcodes
12173                          */
12174                 case MONO_CUSTOM_PREFIX: {
12175
12176                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
12177
12178                         CHECK_OPSIZE (2);
12179                         switch (ip [1]) {
12180                         case CEE_MONO_ICALL: {
12181                                 gpointer func;
12182                                 MonoJitICallInfo *info;
12183
12184                                 token = read32 (ip + 2);
12185                                 func = mono_method_get_wrapper_data (method, token);
12186                                 info = mono_find_jit_icall_by_addr (func);
12187                                 if (!info)
12188                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
12189                                 g_assert (info);
12190
12191                                 CHECK_STACK (info->sig->param_count);
12192                                 sp -= info->sig->param_count;
12193
12194                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
12195                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
12196                                         *sp++ = ins;
12197
12198                                 ip += 6;
12199                                 inline_costs += 10 * num_calls++;
12200
12201                                 break;
12202                         }
12203                         case CEE_MONO_LDPTR_CARD_TABLE:
12204                         case CEE_MONO_LDPTR_NURSERY_START:
12205                         case CEE_MONO_LDPTR_NURSERY_BITS:
12206                         case CEE_MONO_LDPTR_INT_REQ_FLAG: {
12207                                 CHECK_STACK_OVF (1);
12208
12209                                 switch (ip [1]) {
12210                                         case CEE_MONO_LDPTR_CARD_TABLE:
12211                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR, NULL);
12212                                                 break;
12213                                         case CEE_MONO_LDPTR_NURSERY_START:
12214                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_START, NULL);
12215                                                 break;
12216                                         case CEE_MONO_LDPTR_NURSERY_BITS:
12217                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_GC_NURSERY_BITS, NULL);
12218                                                 break;
12219                                         case CEE_MONO_LDPTR_INT_REQ_FLAG:
12220                                                 ins = emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
12221                                                 break;
12222                                 }
12223
12224                                 *sp++ = ins;
12225                                 ip += 2;
12226                                 inline_costs += 10 * num_calls++;
12227                                 break;
12228                         }
12229                         case CEE_MONO_LDPTR: {
12230                                 gpointer ptr;
12231
12232                                 CHECK_STACK_OVF (1);
12233                                 CHECK_OPSIZE (6);
12234                                 token = read32 (ip + 2);
12235
12236                                 ptr = mono_method_get_wrapper_data (method, token);
12237                                 EMIT_NEW_PCONST (cfg, ins, ptr);
12238                                 *sp++ = ins;
12239                                 ip += 6;
12240                                 inline_costs += 10 * num_calls++;
12241                                 /* Can't embed random pointers into AOT code */
12242                                 DISABLE_AOT (cfg);
12243                                 break;
12244                         }
12245                         case CEE_MONO_JIT_ICALL_ADDR: {
12246                                 MonoJitICallInfo *callinfo;
12247                                 gpointer ptr;
12248
12249                                 CHECK_STACK_OVF (1);
12250                                 CHECK_OPSIZE (6);
12251                                 token = read32 (ip + 2);
12252
12253                                 ptr = mono_method_get_wrapper_data (method, token);
12254                                 callinfo = mono_find_jit_icall_by_addr (ptr);
12255                                 g_assert (callinfo);
12256                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
12257                                 *sp++ = ins;
12258                                 ip += 6;
12259                                 inline_costs += 10 * num_calls++;
12260                                 break;
12261                         }
12262                         case CEE_MONO_ICALL_ADDR: {
12263                                 MonoMethod *cmethod;
12264                                 gpointer ptr;
12265
12266                                 CHECK_STACK_OVF (1);
12267                                 CHECK_OPSIZE (6);
12268                                 token = read32 (ip + 2);
12269
12270                                 cmethod = (MonoMethod *)mono_method_get_wrapper_data (method, token);
12271
12272                                 if (cfg->compile_aot) {
12273                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
12274                                 } else {
12275                                         ptr = mono_lookup_internal_call (cmethod);
12276                                         g_assert (ptr);
12277                                         EMIT_NEW_PCONST (cfg, ins, ptr);
12278                                 }
12279                                 *sp++ = ins;
12280                                 ip += 6;
12281                                 break;
12282                         }
12283                         case CEE_MONO_VTADDR: {
12284                                 MonoInst *src_var, *src;
12285
12286                                 CHECK_STACK (1);
12287                                 --sp;
12288
12289                                 // FIXME:
12290                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
12291                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
12292                                 *sp++ = src;
12293                                 ip += 2;
12294                                 break;
12295                         }
12296                         case CEE_MONO_NEWOBJ: {
12297                                 MonoInst *iargs [2];
12298
12299                                 CHECK_STACK_OVF (1);
12300                                 CHECK_OPSIZE (6);
12301                                 token = read32 (ip + 2);
12302                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12303                                 mono_class_init (klass);
12304                                 NEW_DOMAINCONST (cfg, iargs [0]);
12305                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
12306                                 NEW_CLASSCONST (cfg, iargs [1], klass);
12307                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
12308                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
12309                                 ip += 6;
12310                                 inline_costs += 10 * num_calls++;
12311                                 break;
12312                         }
12313                         case CEE_MONO_OBJADDR:
12314                                 CHECK_STACK (1);
12315                                 --sp;
12316                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
12317                                 ins->dreg = alloc_ireg_mp (cfg);
12318                                 ins->sreg1 = sp [0]->dreg;
12319                                 ins->type = STACK_MP;
12320                                 MONO_ADD_INS (cfg->cbb, ins);
12321                                 *sp++ = ins;
12322                                 ip += 2;
12323                                 break;
12324                         case CEE_MONO_LDNATIVEOBJ:
12325                                 /*
12326                                  * Similar to LDOBJ, but instead load the unmanaged 
12327                                  * representation of the vtype to the stack.
12328                                  */
12329                                 CHECK_STACK (1);
12330                                 CHECK_OPSIZE (6);
12331                                 --sp;
12332                                 token = read32 (ip + 2);
12333                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12334                                 g_assert (klass->valuetype);
12335                                 mono_class_init (klass);
12336
12337                                 {
12338                                         MonoInst *src, *dest, *temp;
12339
12340                                         src = sp [0];
12341                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
12342                                         temp->backend.is_pinvoke = 1;
12343                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
12344                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
12345
12346                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
12347                                         dest->type = STACK_VTYPE;
12348                                         dest->klass = klass;
12349
12350                                         *sp ++ = dest;
12351                                         ip += 6;
12352                                 }
12353                                 break;
12354                         case CEE_MONO_RETOBJ: {
12355                                 /*
12356                                  * Same as RET, but return the native representation of a vtype
12357                                  * to the caller.
12358                                  */
12359                                 g_assert (cfg->ret);
12360                                 g_assert (mono_method_signature (method)->pinvoke); 
12361                                 CHECK_STACK (1);
12362                                 --sp;
12363                                 
12364                                 CHECK_OPSIZE (6);
12365                                 token = read32 (ip + 2);    
12366                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12367
12368                                 if (!cfg->vret_addr) {
12369                                         g_assert (cfg->ret_var_is_local);
12370
12371                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
12372                                 } else {
12373                                         EMIT_NEW_RETLOADA (cfg, ins);
12374                                 }
12375                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
12376                                 
12377                                 if (sp != stack_start)
12378                                         UNVERIFIED;
12379                                 
12380                                 MONO_INST_NEW (cfg, ins, OP_BR);
12381                                 ins->inst_target_bb = end_bblock;
12382                                 MONO_ADD_INS (cfg->cbb, ins);
12383                                 link_bblock (cfg, cfg->cbb, end_bblock);
12384                                 start_new_bblock = 1;
12385                                 ip += 6;
12386                                 break;
12387                         }
12388                         case CEE_MONO_CISINST:
12389                         case CEE_MONO_CCASTCLASS: {
12390                                 int token;
12391                                 CHECK_STACK (1);
12392                                 --sp;
12393                                 CHECK_OPSIZE (6);
12394                                 token = read32 (ip + 2);
12395                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
12396                                 if (ip [1] == CEE_MONO_CISINST)
12397                                         ins = handle_cisinst (cfg, klass, sp [0]);
12398                                 else
12399                                         ins = handle_ccastclass (cfg, klass, sp [0]);
12400                                 *sp++ = ins;
12401                                 ip += 6;
12402                                 break;
12403                         }
12404                         case CEE_MONO_SAVE_LMF:
12405                         case CEE_MONO_RESTORE_LMF:
12406                                 ip += 2;
12407                                 break;
12408                         case CEE_MONO_CLASSCONST:
12409                                 CHECK_STACK_OVF (1);
12410                                 CHECK_OPSIZE (6);
12411                                 token = read32 (ip + 2);
12412                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
12413                                 *sp++ = ins;
12414                                 ip += 6;
12415                                 inline_costs += 10 * num_calls++;
12416                                 break;
12417                         case CEE_MONO_NOT_TAKEN:
12418                                 cfg->cbb->out_of_line = TRUE;
12419                                 ip += 2;
12420                                 break;
12421                         case CEE_MONO_TLS: {
12422                                 MonoTlsKey key;
12423
12424                                 CHECK_STACK_OVF (1);
12425                                 CHECK_OPSIZE (6);
12426                                 key = (MonoTlsKey)read32 (ip + 2);
12427                                 g_assert (key < TLS_KEY_NUM);
12428
12429                                 ins = mono_create_tls_get (cfg, key);
12430                                 if (!ins) {
12431                                         if (cfg->compile_aot) {
12432                                                 DISABLE_AOT (cfg);
12433                                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
12434                                                 ins->dreg = alloc_preg (cfg);
12435                                                 ins->type = STACK_PTR;
12436                                         } else {
12437                                                 g_assert_not_reached ();
12438                                         }
12439                                 }
12440                                 ins->type = STACK_PTR;
12441                                 MONO_ADD_INS (cfg->cbb, ins);
12442                                 *sp++ = ins;
12443                                 ip += 6;
12444                                 break;
12445                         }
12446                         case CEE_MONO_DYN_CALL: {
12447                                 MonoCallInst *call;
12448
12449                                 /* It would be easier to call a trampoline, but that would put an
12450                                  * extra frame on the stack, confusing exception handling. So
12451                                  * implement it inline using an opcode for now.
12452                                  */
12453
12454                                 if (!cfg->dyn_call_var) {
12455                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12456                                         /* prevent it from being register allocated */
12457                                         cfg->dyn_call_var->flags |= MONO_INST_VOLATILE;
12458                                 }
12459
12460                                 /* Has to use a call inst since it local regalloc expects it */
12461                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
12462                                 ins = (MonoInst*)call;
12463                                 sp -= 2;
12464                                 ins->sreg1 = sp [0]->dreg;
12465                                 ins->sreg2 = sp [1]->dreg;
12466                                 MONO_ADD_INS (cfg->cbb, ins);
12467
12468                                 cfg->param_area = MAX (cfg->param_area, cfg->backend->dyn_call_param_area);
12469
12470                                 ip += 2;
12471                                 inline_costs += 10 * num_calls++;
12472
12473                                 break;
12474                         }
12475                         case CEE_MONO_MEMORY_BARRIER: {
12476                                 CHECK_OPSIZE (6);
12477                                 emit_memory_barrier (cfg, (int)read32 (ip + 2));
12478                                 ip += 6;
12479                                 break;
12480                         }
12481                         case CEE_MONO_JIT_ATTACH: {
12482                                 MonoInst *args [16], *domain_ins;
12483                                 MonoInst *ad_ins, *jit_tls_ins;
12484                                 MonoBasicBlock *next_bb = NULL, *call_bb = NULL;
12485
12486                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
12487
12488                                 EMIT_NEW_PCONST (cfg, ins, NULL);
12489                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12490
12491                                 ad_ins = mono_get_domain_intrinsic (cfg);
12492                                 jit_tls_ins = mono_get_jit_tls_intrinsic (cfg);
12493
12494                                 if (cfg->backend->have_tls_get && ad_ins && jit_tls_ins) {
12495                                         NEW_BBLOCK (cfg, next_bb);
12496                                         NEW_BBLOCK (cfg, call_bb);
12497
12498                                         if (cfg->compile_aot) {
12499                                                 /* AOT code is only used in the root domain */
12500                                                 EMIT_NEW_PCONST (cfg, domain_ins, NULL);
12501                                         } else {
12502                                                 EMIT_NEW_PCONST (cfg, domain_ins, cfg->domain);
12503                                         }
12504                                         MONO_ADD_INS (cfg->cbb, ad_ins);
12505                                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, ad_ins->dreg, domain_ins->dreg);
12506                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, call_bb);
12507
12508                                         MONO_ADD_INS (cfg->cbb, jit_tls_ins);
12509                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, jit_tls_ins->dreg, 0);
12510                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, call_bb);
12511
12512                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, next_bb);
12513                                         MONO_START_BB (cfg, call_bb);
12514                                 }
12515
12516                                 if (cfg->compile_aot) {
12517                                         /* AOT code is only used in the root domain */
12518                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
12519                                 } else {
12520                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
12521                                 }
12522                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
12523                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
12524
12525                                 if (next_bb)
12526                                         MONO_START_BB (cfg, next_bb);
12527                                 ip += 2;
12528                                 break;
12529                         }
12530                         case CEE_MONO_JIT_DETACH: {
12531                                 MonoInst *args [16];
12532
12533                                 /* Restore the original domain */
12534                                 dreg = alloc_ireg (cfg);
12535                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
12536                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
12537                                 ip += 2;
12538                                 break;
12539                         }
12540                         default:
12541                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
12542                                 break;
12543                         }
12544                         break;
12545                 }
12546
12547                 case CEE_PREFIX1: {
12548                         CHECK_OPSIZE (2);
12549                         switch (ip [1]) {
12550                         case CEE_ARGLIST: {
12551                                 /* somewhat similar to LDTOKEN */
12552                                 MonoInst *addr, *vtvar;
12553                                 CHECK_STACK_OVF (1);
12554                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
12555
12556                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
12557                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
12558
12559                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
12560                                 ins->type = STACK_VTYPE;
12561                                 ins->klass = mono_defaults.argumenthandle_class;
12562                                 *sp++ = ins;
12563                                 ip += 2;
12564                                 break;
12565                         }
12566                         case CEE_CEQ:
12567                         case CEE_CGT:
12568                         case CEE_CGT_UN:
12569                         case CEE_CLT:
12570                         case CEE_CLT_UN: {
12571                                 MonoInst *cmp, *arg1, *arg2;
12572
12573                                 CHECK_STACK (2);
12574                                 sp -= 2;
12575                                 arg1 = sp [0];
12576                                 arg2 = sp [1];
12577
12578                                 /*
12579                                  * The following transforms:
12580                                  *    CEE_CEQ    into OP_CEQ
12581                                  *    CEE_CGT    into OP_CGT
12582                                  *    CEE_CGT_UN into OP_CGT_UN
12583                                  *    CEE_CLT    into OP_CLT
12584                                  *    CEE_CLT_UN into OP_CLT_UN
12585                                  */
12586                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
12587
12588                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
12589                                 cmp->sreg1 = arg1->dreg;
12590                                 cmp->sreg2 = arg2->dreg;
12591                                 type_from_op (cfg, cmp, arg1, arg2);
12592                                 CHECK_TYPE (cmp);
12593                                 add_widen_op (cfg, cmp, &arg1, &arg2);
12594                                 if ((arg1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((arg1->type == STACK_PTR) || (arg1->type == STACK_OBJ) || (arg1->type == STACK_MP))))
12595                                         cmp->opcode = OP_LCOMPARE;
12596                                 else if (arg1->type == STACK_R4)
12597                                         cmp->opcode = OP_RCOMPARE;
12598                                 else if (arg1->type == STACK_R8)
12599                                         cmp->opcode = OP_FCOMPARE;
12600                                 else
12601                                         cmp->opcode = OP_ICOMPARE;
12602                                 MONO_ADD_INS (cfg->cbb, cmp);
12603                                 ins->type = STACK_I4;
12604                                 ins->dreg = alloc_dreg (cfg, (MonoStackType)ins->type);
12605                                 type_from_op (cfg, ins, arg1, arg2);
12606
12607                                 if (cmp->opcode == OP_FCOMPARE || cmp->opcode == OP_RCOMPARE) {
12608                                         /*
12609                                          * The backends expect the fceq opcodes to do the
12610                                          * comparison too.
12611                                          */
12612                                         ins->sreg1 = cmp->sreg1;
12613                                         ins->sreg2 = cmp->sreg2;
12614                                         NULLIFY_INS (cmp);
12615                                 }
12616                                 MONO_ADD_INS (cfg->cbb, ins);
12617                                 *sp++ = ins;
12618                                 ip += 2;
12619                                 break;
12620                         }
12621                         case CEE_LDFTN: {
12622                                 MonoInst *argconst;
12623                                 MonoMethod *cil_method;
12624
12625                                 CHECK_STACK_OVF (1);
12626                                 CHECK_OPSIZE (6);
12627                                 n = read32 (ip + 2);
12628                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12629                                 if (!cmethod || mono_loader_get_last_error ())
12630                                         LOAD_ERROR;
12631                                 mono_class_init (cmethod->klass);
12632
12633                                 mono_save_token_info (cfg, image, n, cmethod);
12634
12635                                 context_used = mini_method_check_context_used (cfg, cmethod);
12636
12637                                 cil_method = cmethod;
12638                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
12639                                         METHOD_ACCESS_FAILURE (method, cil_method);
12640
12641                                 if (mono_security_core_clr_enabled ())
12642                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12643
12644                                 /* 
12645                                  * Optimize the common case of ldftn+delegate creation
12646                                  */
12647                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
12648                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12649                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12650                                                 MonoInst *target_ins, *handle_ins;
12651                                                 MonoMethod *invoke;
12652                                                 int invoke_context_used;
12653
12654                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12655                                                 if (!invoke || !mono_method_signature (invoke))
12656                                                         LOAD_ERROR;
12657
12658                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12659
12660                                                 target_ins = sp [-1];
12661
12662                                                 if (mono_security_core_clr_enabled ())
12663                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12664
12665                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
12666                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
12667                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
12668                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
12669                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
12670                                                         }
12671                                                 }
12672
12673                                                 /* FIXME: SGEN support */
12674                                                 if (invoke_context_used == 0) {
12675                                                         ip += 6;
12676                                                         if (cfg->verbose_level > 3)
12677                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12678                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, FALSE))) {
12679                                                                 sp --;
12680                                                                 *sp = handle_ins;
12681                                                                 CHECK_CFG_EXCEPTION;
12682                                                                 ip += 5;
12683                                                                 sp ++;
12684                                                                 break;
12685                                                         }
12686                                                         ip -= 6;
12687                                                 }
12688                                         }
12689                                 }
12690
12691                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
12692                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
12693                                 *sp++ = ins;
12694                                 
12695                                 ip += 6;
12696                                 inline_costs += 10 * num_calls++;
12697                                 break;
12698                         }
12699                         case CEE_LDVIRTFTN: {
12700                                 MonoInst *args [2];
12701
12702                                 CHECK_STACK (1);
12703                                 CHECK_OPSIZE (6);
12704                                 n = read32 (ip + 2);
12705                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
12706                                 if (!cmethod || mono_loader_get_last_error ())
12707                                         LOAD_ERROR;
12708                                 mono_class_init (cmethod->klass);
12709  
12710                                 context_used = mini_method_check_context_used (cfg, cmethod);
12711
12712                                 if (mono_security_core_clr_enabled ())
12713                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod);
12714
12715                                 /*
12716                                  * Optimize the common case of ldvirtftn+delegate creation
12717                                  */
12718                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, cfg->cbb, ip + 6) && (ip [6] == CEE_NEWOBJ) && (ip > header->code && ip [-1] == CEE_DUP)) {
12719                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
12720                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
12721                                                 MonoInst *target_ins, *handle_ins;
12722                                                 MonoMethod *invoke;
12723                                                 int invoke_context_used;
12724                                                 gboolean is_virtual = cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL;
12725
12726                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
12727                                                 if (!invoke || !mono_method_signature (invoke))
12728                                                         LOAD_ERROR;
12729
12730                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
12731
12732                                                 target_ins = sp [-1];
12733
12734                                                 if (mono_security_core_clr_enabled ())
12735                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method);
12736
12737                                                 /* FIXME: SGEN support */
12738                                                 if (invoke_context_used == 0 || cfg->llvm_only) {
12739                                                         ip += 6;
12740                                                         if (cfg->verbose_level > 3)
12741                                                                 g_print ("converting (in B%d: stack: %d) %s", cfg->cbb->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
12742                                                         if ((handle_ins = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used, is_virtual))) {
12743                                                                 sp -= 2;
12744                                                                 *sp = handle_ins;
12745                                                                 CHECK_CFG_EXCEPTION;
12746                                                                 ip += 5;
12747                                                                 sp ++;
12748                                                                 break;
12749                                                         }
12750                                                         ip -= 6;
12751                                                 }
12752                                         }
12753                                 }
12754
12755                                 --sp;
12756                                 args [0] = *sp;
12757
12758                                 args [1] = emit_get_rgctx_method (cfg, context_used,
12759                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
12760
12761                                 if (context_used)
12762                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
12763                                 else
12764                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
12765
12766                                 ip += 6;
12767                                 inline_costs += 10 * num_calls++;
12768                                 break;
12769                         }
12770                         case CEE_LDARG:
12771                                 CHECK_STACK_OVF (1);
12772                                 CHECK_OPSIZE (4);
12773                                 n = read16 (ip + 2);
12774                                 CHECK_ARG (n);
12775                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
12776                                 *sp++ = ins;
12777                                 ip += 4;
12778                                 break;
12779                         case CEE_LDARGA:
12780                                 CHECK_STACK_OVF (1);
12781                                 CHECK_OPSIZE (4);
12782                                 n = read16 (ip + 2);
12783                                 CHECK_ARG (n);
12784                                 NEW_ARGLOADA (cfg, ins, n);
12785                                 MONO_ADD_INS (cfg->cbb, ins);
12786                                 *sp++ = ins;
12787                                 ip += 4;
12788                                 break;
12789                         case CEE_STARG:
12790                                 CHECK_STACK (1);
12791                                 --sp;
12792                                 CHECK_OPSIZE (4);
12793                                 n = read16 (ip + 2);
12794                                 CHECK_ARG (n);
12795                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
12796                                         UNVERIFIED;
12797                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
12798                                 ip += 4;
12799                                 break;
12800                         case CEE_LDLOC:
12801                                 CHECK_STACK_OVF (1);
12802                                 CHECK_OPSIZE (4);
12803                                 n = read16 (ip + 2);
12804                                 CHECK_LOCAL (n);
12805                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
12806                                 *sp++ = ins;
12807                                 ip += 4;
12808                                 break;
12809                         case CEE_LDLOCA: {
12810                                 unsigned char *tmp_ip;
12811                                 CHECK_STACK_OVF (1);
12812                                 CHECK_OPSIZE (4);
12813                                 n = read16 (ip + 2);
12814                                 CHECK_LOCAL (n);
12815
12816                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
12817                                         ip = tmp_ip;
12818                                         inline_costs += 1;
12819                                         break;
12820                                 }                       
12821                                 
12822                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
12823                                 *sp++ = ins;
12824                                 ip += 4;
12825                                 break;
12826                         }
12827                         case CEE_STLOC:
12828                                 CHECK_STACK (1);
12829                                 --sp;
12830                                 CHECK_OPSIZE (4);
12831                                 n = read16 (ip + 2);
12832                                 CHECK_LOCAL (n);
12833                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
12834                                         UNVERIFIED;
12835                                 emit_stloc_ir (cfg, sp, header, n);
12836                                 ip += 4;
12837                                 inline_costs += 1;
12838                                 break;
12839                         case CEE_LOCALLOC:
12840                                 CHECK_STACK (1);
12841                                 --sp;
12842                                 if (sp != stack_start) 
12843                                         UNVERIFIED;
12844                                 if (cfg->method != method) 
12845                                         /* 
12846                                          * Inlining this into a loop in a parent could lead to 
12847                                          * stack overflows which is different behavior than the
12848                                          * non-inlined case, thus disable inlining in this case.
12849                                          */
12850                                         INLINE_FAILURE("localloc");
12851
12852                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
12853                                 ins->dreg = alloc_preg (cfg);
12854                                 ins->sreg1 = sp [0]->dreg;
12855                                 ins->type = STACK_PTR;
12856                                 MONO_ADD_INS (cfg->cbb, ins);
12857
12858                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
12859                                 if (init_locals)
12860                                         ins->flags |= MONO_INST_INIT;
12861
12862                                 *sp++ = ins;
12863                                 ip += 2;
12864                                 break;
12865                         case CEE_ENDFILTER: {
12866                                 MonoExceptionClause *clause, *nearest;
12867                                 int cc;
12868
12869                                 CHECK_STACK (1);
12870                                 --sp;
12871                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
12872                                         UNVERIFIED;
12873                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
12874                                 ins->sreg1 = (*sp)->dreg;
12875                                 MONO_ADD_INS (cfg->cbb, ins);
12876                                 start_new_bblock = 1;
12877                                 ip += 2;
12878
12879                                 nearest = NULL;
12880                                 for (cc = 0; cc < header->num_clauses; ++cc) {
12881                                         clause = &header->clauses [cc];
12882                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
12883                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
12884                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset)))
12885                                                 nearest = clause;
12886                                 }
12887                                 g_assert (nearest);
12888                                 if ((ip - header->code) != nearest->handler_offset)
12889                                         UNVERIFIED;
12890
12891                                 break;
12892                         }
12893                         case CEE_UNALIGNED_:
12894                                 ins_flag |= MONO_INST_UNALIGNED;
12895                                 /* FIXME: record alignment? we can assume 1 for now */
12896                                 CHECK_OPSIZE (3);
12897                                 ip += 3;
12898                                 break;
12899                         case CEE_VOLATILE_:
12900                                 ins_flag |= MONO_INST_VOLATILE;
12901                                 ip += 2;
12902                                 break;
12903                         case CEE_TAIL_:
12904                                 ins_flag   |= MONO_INST_TAILCALL;
12905                                 cfg->flags |= MONO_CFG_HAS_TAIL;
12906                                 /* Can't inline tail calls at this time */
12907                                 inline_costs += 100000;
12908                                 ip += 2;
12909                                 break;
12910                         case CEE_INITOBJ:
12911                                 CHECK_STACK (1);
12912                                 --sp;
12913                                 CHECK_OPSIZE (6);
12914                                 token = read32 (ip + 2);
12915                                 klass = mini_get_class (method, token, generic_context);
12916                                 CHECK_TYPELOAD (klass);
12917                                 if (generic_class_is_reference_type (cfg, klass))
12918                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
12919                                 else
12920                                         mini_emit_initobj (cfg, *sp, NULL, klass);
12921                                 ip += 6;
12922                                 inline_costs += 1;
12923                                 break;
12924                         case CEE_CONSTRAINED_:
12925                                 CHECK_OPSIZE (6);
12926                                 token = read32 (ip + 2);
12927                                 constrained_class = mini_get_class (method, token, generic_context);
12928                                 CHECK_TYPELOAD (constrained_class);
12929                                 ip += 6;
12930                                 break;
12931                         case CEE_CPBLK:
12932                         case CEE_INITBLK: {
12933                                 MonoInst *iargs [3];
12934                                 CHECK_STACK (3);
12935                                 sp -= 3;
12936
12937                                 /* Skip optimized paths for volatile operations. */
12938                                 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)) {
12939                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
12940                                 } 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)) {
12941                                         /* emit_memset only works when val == 0 */
12942                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
12943                                 } else {
12944                                         MonoInst *call;
12945                                         iargs [0] = sp [0];
12946                                         iargs [1] = sp [1];
12947                                         iargs [2] = sp [2];
12948                                         if (ip [1] == CEE_CPBLK) {
12949                                                 /*
12950                                                  * FIXME: It's unclear whether we should be emitting both the acquire
12951                                                  * and release barriers for cpblk. It is technically both a load and
12952                                                  * store operation, so it seems like that's the sensible thing to do.
12953                                                  *
12954                                                  * FIXME: We emit full barriers on both sides of the operation for
12955                                                  * simplicity. We should have a separate atomic memcpy method instead.
12956                                                  */
12957                                                 MonoMethod *memcpy_method = get_memcpy_method ();
12958
12959                                                 if (ins_flag & MONO_INST_VOLATILE)
12960                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12961
12962                                                 call = mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
12963                                                 call->flags |= ins_flag;
12964
12965                                                 if (ins_flag & MONO_INST_VOLATILE)
12966                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_SEQ);
12967                                         } else {
12968                                                 MonoMethod *memset_method = get_memset_method ();
12969                                                 if (ins_flag & MONO_INST_VOLATILE) {
12970                                                         /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
12971                                                         emit_memory_barrier (cfg, MONO_MEMORY_BARRIER_REL);
12972                                                 }
12973                                                 call = mono_emit_method_call (cfg, memset_method, iargs, NULL);
12974                                                 call->flags |= ins_flag;
12975                                         }
12976                                 }
12977                                 ip += 2;
12978                                 ins_flag = 0;
12979                                 inline_costs += 1;
12980                                 break;
12981                         }
12982                         case CEE_NO_:
12983                                 CHECK_OPSIZE (3);
12984                                 if (ip [2] & 0x1)
12985                                         ins_flag |= MONO_INST_NOTYPECHECK;
12986                                 if (ip [2] & 0x2)
12987                                         ins_flag |= MONO_INST_NORANGECHECK;
12988                                 /* we ignore the no-nullcheck for now since we
12989                                  * really do it explicitly only when doing callvirt->call
12990                                  */
12991                                 ip += 3;
12992                                 break;
12993                         case CEE_RETHROW: {
12994                                 MonoInst *load;
12995                                 int handler_offset = -1;
12996
12997                                 for (i = 0; i < header->num_clauses; ++i) {
12998                                         MonoExceptionClause *clause = &header->clauses [i];
12999                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
13000                                                 handler_offset = clause->handler_offset;
13001                                                 break;
13002                                         }
13003                                 }
13004
13005                                 cfg->cbb->flags |= BB_EXCEPTION_UNSAFE;
13006
13007                                 if (handler_offset == -1)
13008                                         UNVERIFIED;
13009
13010                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
13011                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
13012                                 ins->sreg1 = load->dreg;
13013                                 MONO_ADD_INS (cfg->cbb, ins);
13014
13015                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
13016                                 MONO_ADD_INS (cfg->cbb, ins);
13017
13018                                 sp = stack_start;
13019                                 link_bblock (cfg, cfg->cbb, end_bblock);
13020                                 start_new_bblock = 1;
13021                                 ip += 2;
13022                                 break;
13023                         }
13024                         case CEE_SIZEOF: {
13025                                 guint32 val;
13026                                 int ialign;
13027
13028                                 CHECK_STACK_OVF (1);
13029                                 CHECK_OPSIZE (6);
13030                                 token = read32 (ip + 2);
13031                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !image_is_dynamic (method->klass->image) && !generic_context) {
13032                                         MonoType *type = mono_type_create_from_typespec_checked (image, token, &cfg->error);
13033                                         CHECK_CFG_ERROR;
13034
13035                                         val = mono_type_size (type, &ialign);
13036                                 } else {
13037                                         MonoClass *klass = mini_get_class (method, token, generic_context);
13038                                         CHECK_TYPELOAD (klass);
13039
13040                                         val = mono_type_size (&klass->byval_arg, &ialign);
13041
13042                                         if (mini_is_gsharedvt_klass (klass))
13043                                                 GSHAREDVT_FAILURE (*ip);
13044                                 }
13045                                 EMIT_NEW_ICONST (cfg, ins, val);
13046                                 *sp++= ins;
13047                                 ip += 6;
13048                                 break;
13049                         }
13050                         case CEE_REFANYTYPE: {
13051                                 MonoInst *src_var, *src;
13052
13053                                 GSHAREDVT_FAILURE (*ip);
13054
13055                                 CHECK_STACK (1);
13056                                 --sp;
13057
13058                                 // FIXME:
13059                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
13060                                 if (!src_var)
13061                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
13062                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
13063                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, MONO_STRUCT_OFFSET (MonoTypedRef, type));
13064                                 *sp++ = ins;
13065                                 ip += 2;
13066                                 break;
13067                         }
13068                         case CEE_READONLY_:
13069                                 readonly = TRUE;
13070                                 ip += 2;
13071                                 break;
13072
13073                         case CEE_UNUSED56:
13074                         case CEE_UNUSED57:
13075                         case CEE_UNUSED70:
13076                         case CEE_UNUSED:
13077                         case CEE_UNUSED99:
13078                                 UNVERIFIED;
13079                                 
13080                         default:
13081                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
13082                                 UNVERIFIED;
13083                         }
13084                         break;
13085                 }
13086                 case CEE_UNUSED58:
13087                 case CEE_UNUSED1:
13088                         UNVERIFIED;
13089
13090                 default:
13091                         g_warning ("opcode 0x%02x not handled", *ip);
13092                         UNVERIFIED;
13093                 }
13094         }
13095         if (start_new_bblock != 1)
13096                 UNVERIFIED;
13097
13098         cfg->cbb->cil_length = ip - cfg->cbb->cil_code;
13099         if (cfg->cbb->next_bb) {
13100                 /* This could already be set because of inlining, #693905 */
13101                 MonoBasicBlock *bb = cfg->cbb;
13102
13103                 while (bb->next_bb)
13104                         bb = bb->next_bb;
13105                 bb->next_bb = end_bblock;
13106         } else {
13107                 cfg->cbb->next_bb = end_bblock;
13108         }
13109
13110         if (cfg->method == method && cfg->domainvar) {
13111                 MonoInst *store;
13112                 MonoInst *get_domain;
13113
13114                 cfg->cbb = init_localsbb;
13115
13116                 if ((get_domain = mono_get_domain_intrinsic (cfg))) {
13117                         MONO_ADD_INS (cfg->cbb, get_domain);
13118                 } else {
13119                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
13120                 }
13121                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
13122                 MONO_ADD_INS (cfg->cbb, store);
13123         }
13124
13125 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
13126         if (cfg->compile_aot)
13127                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
13128                 mono_get_got_var (cfg);
13129 #endif
13130
13131         if (cfg->method == method && cfg->got_var)
13132                 mono_emit_load_got_addr (cfg);
13133
13134         if (init_localsbb) {
13135                 cfg->cbb = init_localsbb;
13136                 cfg->ip = NULL;
13137                 for (i = 0; i < header->num_locals; ++i) {
13138                         emit_init_local (cfg, i, header->locals [i], init_locals);
13139                 }
13140         }
13141
13142         if (cfg->init_ref_vars && cfg->method == method) {
13143                 /* Emit initialization for ref vars */
13144                 // FIXME: Avoid duplication initialization for IL locals.
13145                 for (i = 0; i < cfg->num_varinfo; ++i) {
13146                         MonoInst *ins = cfg->varinfo [i];
13147
13148                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
13149                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
13150                 }
13151         }
13152
13153         if (cfg->lmf_var && cfg->method == method && !cfg->llvm_only) {
13154                 cfg->cbb = init_localsbb;
13155                 emit_push_lmf (cfg);
13156         }
13157
13158         cfg->cbb = init_localsbb;
13159         emit_instrumentation_call (cfg, mono_profiler_method_enter);
13160
13161         if (seq_points) {
13162                 MonoBasicBlock *bb;
13163
13164                 /*
13165                  * Make seq points at backward branch targets interruptable.
13166                  */
13167                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
13168                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
13169                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
13170         }
13171
13172         /* Add a sequence point for method entry/exit events */
13173         if (seq_points && cfg->gen_sdb_seq_points) {
13174                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
13175                 MONO_ADD_INS (init_localsbb, ins);
13176                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
13177                 MONO_ADD_INS (cfg->bb_exit, ins);
13178         }
13179
13180         /*
13181          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
13182          * the code they refer to was dead (#11880).
13183          */
13184         if (sym_seq_points) {
13185                 for (i = 0; i < header->code_size; ++i) {
13186                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
13187                                 MonoInst *ins;
13188
13189                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
13190                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
13191                         }
13192                 }
13193         }
13194
13195         cfg->ip = NULL;
13196
13197         if (cfg->method == method) {
13198                 MonoBasicBlock *bb;
13199                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13200                         bb->region = mono_find_block_region (cfg, bb->real_offset);
13201                         if (cfg->spvars)
13202                                 mono_create_spvar_for_region (cfg, bb->region);
13203                         if (cfg->verbose_level > 2)
13204                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
13205                 }
13206         }
13207
13208         if (inline_costs < 0) {
13209                 char *mname;
13210
13211                 /* Method is too large */
13212                 mname = mono_method_full_name (method, TRUE);
13213                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
13214                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
13215                 g_free (mname);
13216         }
13217
13218         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
13219                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
13220
13221         goto cleanup;
13222
13223 mono_error_exit:
13224         g_assert (!mono_error_ok (&cfg->error));
13225         goto cleanup;
13226  
13227  exception_exit:
13228         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
13229         goto cleanup;
13230
13231  unverified:
13232         set_exception_type_from_invalid_il (cfg, method, ip);
13233         goto cleanup;
13234
13235  cleanup:
13236         g_slist_free (class_inits);
13237         mono_basic_block_free (original_bb);
13238         cfg->dont_inline = g_list_remove (cfg->dont_inline, method);
13239         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
13240         if (cfg->exception_type)
13241                 return -1;
13242         else
13243                 return inline_costs;
13244 }
13245
13246 static int
13247 store_membase_reg_to_store_membase_imm (int opcode)
13248 {
13249         switch (opcode) {
13250         case OP_STORE_MEMBASE_REG:
13251                 return OP_STORE_MEMBASE_IMM;
13252         case OP_STOREI1_MEMBASE_REG:
13253                 return OP_STOREI1_MEMBASE_IMM;
13254         case OP_STOREI2_MEMBASE_REG:
13255                 return OP_STOREI2_MEMBASE_IMM;
13256         case OP_STOREI4_MEMBASE_REG:
13257                 return OP_STOREI4_MEMBASE_IMM;
13258         case OP_STOREI8_MEMBASE_REG:
13259                 return OP_STOREI8_MEMBASE_IMM;
13260         default:
13261                 g_assert_not_reached ();
13262         }
13263
13264         return -1;
13265 }               
13266
13267 int
13268 mono_op_to_op_imm (int opcode)
13269 {
13270         switch (opcode) {
13271         case OP_IADD:
13272                 return OP_IADD_IMM;
13273         case OP_ISUB:
13274                 return OP_ISUB_IMM;
13275         case OP_IDIV:
13276                 return OP_IDIV_IMM;
13277         case OP_IDIV_UN:
13278                 return OP_IDIV_UN_IMM;
13279         case OP_IREM:
13280                 return OP_IREM_IMM;
13281         case OP_IREM_UN:
13282                 return OP_IREM_UN_IMM;
13283         case OP_IMUL:
13284                 return OP_IMUL_IMM;
13285         case OP_IAND:
13286                 return OP_IAND_IMM;
13287         case OP_IOR:
13288                 return OP_IOR_IMM;
13289         case OP_IXOR:
13290                 return OP_IXOR_IMM;
13291         case OP_ISHL:
13292                 return OP_ISHL_IMM;
13293         case OP_ISHR:
13294                 return OP_ISHR_IMM;
13295         case OP_ISHR_UN:
13296                 return OP_ISHR_UN_IMM;
13297
13298         case OP_LADD:
13299                 return OP_LADD_IMM;
13300         case OP_LSUB:
13301                 return OP_LSUB_IMM;
13302         case OP_LAND:
13303                 return OP_LAND_IMM;
13304         case OP_LOR:
13305                 return OP_LOR_IMM;
13306         case OP_LXOR:
13307                 return OP_LXOR_IMM;
13308         case OP_LSHL:
13309                 return OP_LSHL_IMM;
13310         case OP_LSHR:
13311                 return OP_LSHR_IMM;
13312         case OP_LSHR_UN:
13313                 return OP_LSHR_UN_IMM;
13314 #if SIZEOF_REGISTER == 8
13315         case OP_LREM:
13316                 return OP_LREM_IMM;
13317 #endif
13318
13319         case OP_COMPARE:
13320                 return OP_COMPARE_IMM;
13321         case OP_ICOMPARE:
13322                 return OP_ICOMPARE_IMM;
13323         case OP_LCOMPARE:
13324                 return OP_LCOMPARE_IMM;
13325
13326         case OP_STORE_MEMBASE_REG:
13327                 return OP_STORE_MEMBASE_IMM;
13328         case OP_STOREI1_MEMBASE_REG:
13329                 return OP_STOREI1_MEMBASE_IMM;
13330         case OP_STOREI2_MEMBASE_REG:
13331                 return OP_STOREI2_MEMBASE_IMM;
13332         case OP_STOREI4_MEMBASE_REG:
13333                 return OP_STOREI4_MEMBASE_IMM;
13334
13335 #if defined(TARGET_X86) || defined (TARGET_AMD64)
13336         case OP_X86_PUSH:
13337                 return OP_X86_PUSH_IMM;
13338         case OP_X86_COMPARE_MEMBASE_REG:
13339                 return OP_X86_COMPARE_MEMBASE_IMM;
13340 #endif
13341 #if defined(TARGET_AMD64)
13342         case OP_AMD64_ICOMPARE_MEMBASE_REG:
13343                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13344 #endif
13345         case OP_VOIDCALL_REG:
13346                 return OP_VOIDCALL;
13347         case OP_CALL_REG:
13348                 return OP_CALL;
13349         case OP_LCALL_REG:
13350                 return OP_LCALL;
13351         case OP_FCALL_REG:
13352                 return OP_FCALL;
13353         case OP_LOCALLOC:
13354                 return OP_LOCALLOC_IMM;
13355         }
13356
13357         return -1;
13358 }
13359
13360 static int
13361 ldind_to_load_membase (int opcode)
13362 {
13363         switch (opcode) {
13364         case CEE_LDIND_I1:
13365                 return OP_LOADI1_MEMBASE;
13366         case CEE_LDIND_U1:
13367                 return OP_LOADU1_MEMBASE;
13368         case CEE_LDIND_I2:
13369                 return OP_LOADI2_MEMBASE;
13370         case CEE_LDIND_U2:
13371                 return OP_LOADU2_MEMBASE;
13372         case CEE_LDIND_I4:
13373                 return OP_LOADI4_MEMBASE;
13374         case CEE_LDIND_U4:
13375                 return OP_LOADU4_MEMBASE;
13376         case CEE_LDIND_I:
13377                 return OP_LOAD_MEMBASE;
13378         case CEE_LDIND_REF:
13379                 return OP_LOAD_MEMBASE;
13380         case CEE_LDIND_I8:
13381                 return OP_LOADI8_MEMBASE;
13382         case CEE_LDIND_R4:
13383                 return OP_LOADR4_MEMBASE;
13384         case CEE_LDIND_R8:
13385                 return OP_LOADR8_MEMBASE;
13386         default:
13387                 g_assert_not_reached ();
13388         }
13389
13390         return -1;
13391 }
13392
13393 static int
13394 stind_to_store_membase (int opcode)
13395 {
13396         switch (opcode) {
13397         case CEE_STIND_I1:
13398                 return OP_STOREI1_MEMBASE_REG;
13399         case CEE_STIND_I2:
13400                 return OP_STOREI2_MEMBASE_REG;
13401         case CEE_STIND_I4:
13402                 return OP_STOREI4_MEMBASE_REG;
13403         case CEE_STIND_I:
13404         case CEE_STIND_REF:
13405                 return OP_STORE_MEMBASE_REG;
13406         case CEE_STIND_I8:
13407                 return OP_STOREI8_MEMBASE_REG;
13408         case CEE_STIND_R4:
13409                 return OP_STORER4_MEMBASE_REG;
13410         case CEE_STIND_R8:
13411                 return OP_STORER8_MEMBASE_REG;
13412         default:
13413                 g_assert_not_reached ();
13414         }
13415
13416         return -1;
13417 }
13418
13419 int
13420 mono_load_membase_to_load_mem (int opcode)
13421 {
13422         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
13423 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13424         switch (opcode) {
13425         case OP_LOAD_MEMBASE:
13426                 return OP_LOAD_MEM;
13427         case OP_LOADU1_MEMBASE:
13428                 return OP_LOADU1_MEM;
13429         case OP_LOADU2_MEMBASE:
13430                 return OP_LOADU2_MEM;
13431         case OP_LOADI4_MEMBASE:
13432                 return OP_LOADI4_MEM;
13433         case OP_LOADU4_MEMBASE:
13434                 return OP_LOADU4_MEM;
13435 #if SIZEOF_REGISTER == 8
13436         case OP_LOADI8_MEMBASE:
13437                 return OP_LOADI8_MEM;
13438 #endif
13439         }
13440 #endif
13441
13442         return -1;
13443 }
13444
13445 static inline int
13446 op_to_op_dest_membase (int store_opcode, int opcode)
13447 {
13448 #if defined(TARGET_X86)
13449         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
13450                 return -1;
13451
13452         switch (opcode) {
13453         case OP_IADD:
13454                 return OP_X86_ADD_MEMBASE_REG;
13455         case OP_ISUB:
13456                 return OP_X86_SUB_MEMBASE_REG;
13457         case OP_IAND:
13458                 return OP_X86_AND_MEMBASE_REG;
13459         case OP_IOR:
13460                 return OP_X86_OR_MEMBASE_REG;
13461         case OP_IXOR:
13462                 return OP_X86_XOR_MEMBASE_REG;
13463         case OP_ADD_IMM:
13464         case OP_IADD_IMM:
13465                 return OP_X86_ADD_MEMBASE_IMM;
13466         case OP_SUB_IMM:
13467         case OP_ISUB_IMM:
13468                 return OP_X86_SUB_MEMBASE_IMM;
13469         case OP_AND_IMM:
13470         case OP_IAND_IMM:
13471                 return OP_X86_AND_MEMBASE_IMM;
13472         case OP_OR_IMM:
13473         case OP_IOR_IMM:
13474                 return OP_X86_OR_MEMBASE_IMM;
13475         case OP_XOR_IMM:
13476         case OP_IXOR_IMM:
13477                 return OP_X86_XOR_MEMBASE_IMM;
13478         case OP_MOVE:
13479                 return OP_NOP;
13480         }
13481 #endif
13482
13483 #if defined(TARGET_AMD64)
13484         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
13485                 return -1;
13486
13487         switch (opcode) {
13488         case OP_IADD:
13489                 return OP_X86_ADD_MEMBASE_REG;
13490         case OP_ISUB:
13491                 return OP_X86_SUB_MEMBASE_REG;
13492         case OP_IAND:
13493                 return OP_X86_AND_MEMBASE_REG;
13494         case OP_IOR:
13495                 return OP_X86_OR_MEMBASE_REG;
13496         case OP_IXOR:
13497                 return OP_X86_XOR_MEMBASE_REG;
13498         case OP_IADD_IMM:
13499                 return OP_X86_ADD_MEMBASE_IMM;
13500         case OP_ISUB_IMM:
13501                 return OP_X86_SUB_MEMBASE_IMM;
13502         case OP_IAND_IMM:
13503                 return OP_X86_AND_MEMBASE_IMM;
13504         case OP_IOR_IMM:
13505                 return OP_X86_OR_MEMBASE_IMM;
13506         case OP_IXOR_IMM:
13507                 return OP_X86_XOR_MEMBASE_IMM;
13508         case OP_LADD:
13509                 return OP_AMD64_ADD_MEMBASE_REG;
13510         case OP_LSUB:
13511                 return OP_AMD64_SUB_MEMBASE_REG;
13512         case OP_LAND:
13513                 return OP_AMD64_AND_MEMBASE_REG;
13514         case OP_LOR:
13515                 return OP_AMD64_OR_MEMBASE_REG;
13516         case OP_LXOR:
13517                 return OP_AMD64_XOR_MEMBASE_REG;
13518         case OP_ADD_IMM:
13519         case OP_LADD_IMM:
13520                 return OP_AMD64_ADD_MEMBASE_IMM;
13521         case OP_SUB_IMM:
13522         case OP_LSUB_IMM:
13523                 return OP_AMD64_SUB_MEMBASE_IMM;
13524         case OP_AND_IMM:
13525         case OP_LAND_IMM:
13526                 return OP_AMD64_AND_MEMBASE_IMM;
13527         case OP_OR_IMM:
13528         case OP_LOR_IMM:
13529                 return OP_AMD64_OR_MEMBASE_IMM;
13530         case OP_XOR_IMM:
13531         case OP_LXOR_IMM:
13532                 return OP_AMD64_XOR_MEMBASE_IMM;
13533         case OP_MOVE:
13534                 return OP_NOP;
13535         }
13536 #endif
13537
13538         return -1;
13539 }
13540
13541 static inline int
13542 op_to_op_store_membase (int store_opcode, int opcode)
13543 {
13544 #if defined(TARGET_X86) || defined(TARGET_AMD64)
13545         switch (opcode) {
13546         case OP_ICEQ:
13547                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13548                         return OP_X86_SETEQ_MEMBASE;
13549         case OP_CNE:
13550                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
13551                         return OP_X86_SETNE_MEMBASE;
13552         }
13553 #endif
13554
13555         return -1;
13556 }
13557
13558 static inline int
13559 op_to_op_src1_membase (MonoCompile *cfg, int load_opcode, int opcode)
13560 {
13561 #ifdef TARGET_X86
13562         /* FIXME: This has sign extension issues */
13563         /*
13564         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13565                 return OP_X86_COMPARE_MEMBASE8_IMM;
13566         */
13567
13568         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13569                 return -1;
13570
13571         switch (opcode) {
13572         case OP_X86_PUSH:
13573                 return OP_X86_PUSH_MEMBASE;
13574         case OP_COMPARE_IMM:
13575         case OP_ICOMPARE_IMM:
13576                 return OP_X86_COMPARE_MEMBASE_IMM;
13577         case OP_COMPARE:
13578         case OP_ICOMPARE:
13579                 return OP_X86_COMPARE_MEMBASE_REG;
13580         }
13581 #endif
13582
13583 #ifdef TARGET_AMD64
13584         /* FIXME: This has sign extension issues */
13585         /*
13586         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
13587                 return OP_X86_COMPARE_MEMBASE8_IMM;
13588         */
13589
13590         switch (opcode) {
13591         case OP_X86_PUSH:
13592                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13593                         return OP_X86_PUSH_MEMBASE;
13594                 break;
13595                 /* FIXME: This only works for 32 bit immediates
13596         case OP_COMPARE_IMM:
13597         case OP_LCOMPARE_IMM:
13598                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
13599                         return OP_AMD64_COMPARE_MEMBASE_IMM;
13600                 */
13601         case OP_ICOMPARE_IMM:
13602                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13603                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
13604                 break;
13605         case OP_COMPARE:
13606         case OP_LCOMPARE:
13607                 if (cfg->backend->ilp32 && load_opcode == OP_LOAD_MEMBASE)
13608                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13609                 if ((load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32) || (load_opcode == OP_LOADI8_MEMBASE))
13610                         return OP_AMD64_COMPARE_MEMBASE_REG;
13611                 break;
13612         case OP_ICOMPARE:
13613                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
13614                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
13615                 break;
13616         }
13617 #endif
13618
13619         return -1;
13620 }
13621
13622 static inline int
13623 op_to_op_src2_membase (MonoCompile *cfg, int load_opcode, int opcode)
13624 {
13625 #ifdef TARGET_X86
13626         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
13627                 return -1;
13628         
13629         switch (opcode) {
13630         case OP_COMPARE:
13631         case OP_ICOMPARE:
13632                 return OP_X86_COMPARE_REG_MEMBASE;
13633         case OP_IADD:
13634                 return OP_X86_ADD_REG_MEMBASE;
13635         case OP_ISUB:
13636                 return OP_X86_SUB_REG_MEMBASE;
13637         case OP_IAND:
13638                 return OP_X86_AND_REG_MEMBASE;
13639         case OP_IOR:
13640                 return OP_X86_OR_REG_MEMBASE;
13641         case OP_IXOR:
13642                 return OP_X86_XOR_REG_MEMBASE;
13643         }
13644 #endif
13645
13646 #ifdef TARGET_AMD64
13647         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && cfg->backend->ilp32)) {
13648                 switch (opcode) {
13649                 case OP_ICOMPARE:
13650                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
13651                 case OP_IADD:
13652                         return OP_X86_ADD_REG_MEMBASE;
13653                 case OP_ISUB:
13654                         return OP_X86_SUB_REG_MEMBASE;
13655                 case OP_IAND:
13656                         return OP_X86_AND_REG_MEMBASE;
13657                 case OP_IOR:
13658                         return OP_X86_OR_REG_MEMBASE;
13659                 case OP_IXOR:
13660                         return OP_X86_XOR_REG_MEMBASE;
13661                 }
13662         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE && !cfg->backend->ilp32)) {
13663                 switch (opcode) {
13664                 case OP_COMPARE:
13665                 case OP_LCOMPARE:
13666                         return OP_AMD64_COMPARE_REG_MEMBASE;
13667                 case OP_LADD:
13668                         return OP_AMD64_ADD_REG_MEMBASE;
13669                 case OP_LSUB:
13670                         return OP_AMD64_SUB_REG_MEMBASE;
13671                 case OP_LAND:
13672                         return OP_AMD64_AND_REG_MEMBASE;
13673                 case OP_LOR:
13674                         return OP_AMD64_OR_REG_MEMBASE;
13675                 case OP_LXOR:
13676                         return OP_AMD64_XOR_REG_MEMBASE;
13677                 }
13678         }
13679 #endif
13680
13681         return -1;
13682 }
13683
13684 int
13685 mono_op_to_op_imm_noemul (int opcode)
13686 {
13687         switch (opcode) {
13688 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
13689         case OP_LSHR:
13690         case OP_LSHL:
13691         case OP_LSHR_UN:
13692                 return -1;
13693 #endif
13694 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
13695         case OP_IDIV:
13696         case OP_IDIV_UN:
13697         case OP_IREM:
13698         case OP_IREM_UN:
13699                 return -1;
13700 #endif
13701 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
13702         case OP_IMUL:
13703                 return -1;
13704 #endif
13705         default:
13706                 return mono_op_to_op_imm (opcode);
13707         }
13708 }
13709
13710 /**
13711  * mono_handle_global_vregs:
13712  *
13713  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
13714  * for them.
13715  */
13716 void
13717 mono_handle_global_vregs (MonoCompile *cfg)
13718 {
13719         gint32 *vreg_to_bb;
13720         MonoBasicBlock *bb;
13721         int i, pos;
13722
13723         vreg_to_bb = (gint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
13724
13725 #ifdef MONO_ARCH_SIMD_INTRINSICS
13726         if (cfg->uses_simd_intrinsics)
13727                 mono_simd_simplify_indirection (cfg);
13728 #endif
13729
13730         /* Find local vregs used in more than one bb */
13731         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
13732                 MonoInst *ins = bb->code;       
13733                 int block_num = bb->block_num;
13734
13735                 if (cfg->verbose_level > 2)
13736                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
13737
13738                 cfg->cbb = bb;
13739                 for (; ins; ins = ins->next) {
13740                         const char *spec = INS_INFO (ins->opcode);
13741                         int regtype = 0, regindex;
13742                         gint32 prev_bb;
13743
13744                         if (G_UNLIKELY (cfg->verbose_level > 2))
13745                                 mono_print_ins (ins);
13746
13747                         g_assert (ins->opcode >= MONO_CEE_LAST);
13748
13749                         for (regindex = 0; regindex < 4; regindex ++) {
13750                                 int vreg = 0;
13751
13752                                 if (regindex == 0) {
13753                                         regtype = spec [MONO_INST_DEST];
13754                                         if (regtype == ' ')
13755                                                 continue;
13756                                         vreg = ins->dreg;
13757                                 } else if (regindex == 1) {
13758                                         regtype = spec [MONO_INST_SRC1];
13759                                         if (regtype == ' ')
13760                                                 continue;
13761                                         vreg = ins->sreg1;
13762                                 } else if (regindex == 2) {
13763                                         regtype = spec [MONO_INST_SRC2];
13764                                         if (regtype == ' ')
13765                                                 continue;
13766                                         vreg = ins->sreg2;
13767                                 } else if (regindex == 3) {
13768                                         regtype = spec [MONO_INST_SRC3];
13769                                         if (regtype == ' ')
13770                                                 continue;
13771                                         vreg = ins->sreg3;
13772                                 }
13773
13774 #if SIZEOF_REGISTER == 4
13775                                 /* In the LLVM case, the long opcodes are not decomposed */
13776                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
13777                                         /*
13778                                          * Since some instructions reference the original long vreg,
13779                                          * and some reference the two component vregs, it is quite hard
13780                                          * to determine when it needs to be global. So be conservative.
13781                                          */
13782                                         if (!get_vreg_to_inst (cfg, vreg)) {
13783                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13784
13785                                                 if (cfg->verbose_level > 2)
13786                                                         printf ("LONG VREG R%d made global.\n", vreg);
13787                                         }
13788
13789                                         /*
13790                                          * Make the component vregs volatile since the optimizations can
13791                                          * get confused otherwise.
13792                                          */
13793                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
13794                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
13795                                 }
13796 #endif
13797
13798                                 g_assert (vreg != -1);
13799
13800                                 prev_bb = vreg_to_bb [vreg];
13801                                 if (prev_bb == 0) {
13802                                         /* 0 is a valid block num */
13803                                         vreg_to_bb [vreg] = block_num + 1;
13804                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
13805                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
13806                                                 continue;
13807
13808                                         if (!get_vreg_to_inst (cfg, vreg)) {
13809                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13810                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
13811
13812                                                 switch (regtype) {
13813                                                 case 'i':
13814                                                         if (vreg_is_ref (cfg, vreg))
13815                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
13816                                                         else
13817                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
13818                                                         break;
13819                                                 case 'l':
13820                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
13821                                                         break;
13822                                                 case 'f':
13823                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
13824                                                         break;
13825                                                 case 'v':
13826                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
13827                                                         break;
13828                                                 default:
13829                                                         g_assert_not_reached ();
13830                                                 }
13831                                         }
13832
13833                                         /* Flag as having been used in more than one bb */
13834                                         vreg_to_bb [vreg] = -1;
13835                                 }
13836                         }
13837                 }
13838         }
13839
13840         /* If a variable is used in only one bblock, convert it into a local vreg */
13841         for (i = 0; i < cfg->num_varinfo; i++) {
13842                 MonoInst *var = cfg->varinfo [i];
13843                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
13844
13845                 switch (var->type) {
13846                 case STACK_I4:
13847                 case STACK_OBJ:
13848                 case STACK_PTR:
13849                 case STACK_MP:
13850                 case STACK_VTYPE:
13851 #if SIZEOF_REGISTER == 8
13852                 case STACK_I8:
13853 #endif
13854 #if !defined(TARGET_X86)
13855                 /* Enabling this screws up the fp stack on x86 */
13856                 case STACK_R8:
13857 #endif
13858                         if (mono_arch_is_soft_float ())
13859                                 break;
13860
13861                         /* Arguments are implicitly global */
13862                         /* Putting R4 vars into registers doesn't work currently */
13863                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
13864                         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) {
13865                                 /* 
13866                                  * Make that the variable's liveness interval doesn't contain a call, since
13867                                  * that would cause the lvreg to be spilled, making the whole optimization
13868                                  * useless.
13869                                  */
13870                                 /* This is too slow for JIT compilation */
13871 #if 0
13872                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
13873                                         MonoInst *ins;
13874                                         int def_index, call_index, ins_index;
13875                                         gboolean spilled = FALSE;
13876
13877                                         def_index = -1;
13878                                         call_index = -1;
13879                                         ins_index = 0;
13880                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
13881                                                 const char *spec = INS_INFO (ins->opcode);
13882
13883                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
13884                                                         def_index = ins_index;
13885
13886                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
13887                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
13888                                                         if (call_index > def_index) {
13889                                                                 spilled = TRUE;
13890                                                                 break;
13891                                                         }
13892                                                 }
13893
13894                                                 if (MONO_IS_CALL (ins))
13895                                                         call_index = ins_index;
13896
13897                                                 ins_index ++;
13898                                         }
13899
13900                                         if (spilled)
13901                                                 break;
13902                                 }
13903 #endif
13904
13905                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13906                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
13907                                 var->flags |= MONO_INST_IS_DEAD;
13908                                 cfg->vreg_to_inst [var->dreg] = NULL;
13909                         }
13910                         break;
13911                 }
13912         }
13913
13914         /* 
13915          * Compress the varinfo and vars tables so the liveness computation is faster and
13916          * takes up less space.
13917          */
13918         pos = 0;
13919         for (i = 0; i < cfg->num_varinfo; ++i) {
13920                 MonoInst *var = cfg->varinfo [i];
13921                 if (pos < i && cfg->locals_start == i)
13922                         cfg->locals_start = pos;
13923                 if (!(var->flags & MONO_INST_IS_DEAD)) {
13924                         if (pos < i) {
13925                                 cfg->varinfo [pos] = cfg->varinfo [i];
13926                                 cfg->varinfo [pos]->inst_c0 = pos;
13927                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
13928                                 cfg->vars [pos].idx = pos;
13929 #if SIZEOF_REGISTER == 4
13930                                 if (cfg->varinfo [pos]->type == STACK_I8) {
13931                                         /* Modify the two component vars too */
13932                                         MonoInst *var1;
13933
13934                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
13935                                         var1->inst_c0 = pos;
13936                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
13937                                         var1->inst_c0 = pos;
13938                                 }
13939 #endif
13940                         }
13941                         pos ++;
13942                 }
13943         }
13944         cfg->num_varinfo = pos;
13945         if (cfg->locals_start > cfg->num_varinfo)
13946                 cfg->locals_start = cfg->num_varinfo;
13947 }
13948
13949 /**
13950  * mono_spill_global_vars:
13951  *
13952  *   Generate spill code for variables which are not allocated to registers, 
13953  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
13954  * code is generated which could be optimized by the local optimization passes.
13955  */
13956 void
13957 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
13958 {
13959         MonoBasicBlock *bb;
13960         char spec2 [16];
13961         int orig_next_vreg;
13962         guint32 *vreg_to_lvreg;
13963         guint32 *lvregs;
13964         guint32 i, lvregs_len;
13965         gboolean dest_has_lvreg = FALSE;
13966         MonoStackType stacktypes [128];
13967         MonoInst **live_range_start, **live_range_end;
13968         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
13969         int *gsharedvt_vreg_to_idx = NULL;
13970
13971         *need_local_opts = FALSE;
13972
13973         memset (spec2, 0, sizeof (spec2));
13974
13975         /* FIXME: Move this function to mini.c */
13976         stacktypes ['i'] = STACK_PTR;
13977         stacktypes ['l'] = STACK_I8;
13978         stacktypes ['f'] = STACK_R8;
13979 #ifdef MONO_ARCH_SIMD_INTRINSICS
13980         stacktypes ['x'] = STACK_VTYPE;
13981 #endif
13982
13983 #if SIZEOF_REGISTER == 4
13984         /* Create MonoInsts for longs */
13985         for (i = 0; i < cfg->num_varinfo; i++) {
13986                 MonoInst *ins = cfg->varinfo [i];
13987
13988                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
13989                         switch (ins->type) {
13990                         case STACK_R8:
13991                         case STACK_I8: {
13992                                 MonoInst *tree;
13993
13994                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
13995                                         break;
13996
13997                                 g_assert (ins->opcode == OP_REGOFFSET);
13998
13999                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
14000                                 g_assert (tree);
14001                                 tree->opcode = OP_REGOFFSET;
14002                                 tree->inst_basereg = ins->inst_basereg;
14003                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
14004
14005                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
14006                                 g_assert (tree);
14007                                 tree->opcode = OP_REGOFFSET;
14008                                 tree->inst_basereg = ins->inst_basereg;
14009                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
14010                                 break;
14011                         }
14012                         default:
14013                                 break;
14014                         }
14015                 }
14016         }
14017 #endif
14018
14019         if (cfg->compute_gc_maps) {
14020                 /* registers need liveness info even for !non refs */
14021                 for (i = 0; i < cfg->num_varinfo; i++) {
14022                         MonoInst *ins = cfg->varinfo [i];
14023
14024                         if (ins->opcode == OP_REGVAR)
14025                                 ins->flags |= MONO_INST_GC_TRACK;
14026                 }
14027         }
14028
14029         if (cfg->gsharedvt) {
14030                 gsharedvt_vreg_to_idx = (int *)mono_mempool_alloc0 (cfg->mempool, sizeof (int) * cfg->next_vreg);
14031
14032                 for (i = 0; i < cfg->num_varinfo; ++i) {
14033                         MonoInst *ins = cfg->varinfo [i];
14034                         int idx;
14035
14036                         if (mini_is_gsharedvt_variable_type (ins->inst_vtype)) {
14037                                 if (i >= cfg->locals_start) {
14038                                         /* Local */
14039                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
14040                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
14041                                         ins->opcode = OP_GSHAREDVT_LOCAL;
14042                                         ins->inst_imm = idx;
14043                                 } else {
14044                                         /* Arg */
14045                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
14046                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
14047                                 }
14048                         }
14049                 }
14050         }
14051                 
14052         /* FIXME: widening and truncation */
14053
14054         /*
14055          * As an optimization, when a variable allocated to the stack is first loaded into 
14056          * an lvreg, we will remember the lvreg and use it the next time instead of loading
14057          * the variable again.
14058          */
14059         orig_next_vreg = cfg->next_vreg;
14060         vreg_to_lvreg = (guint32 *)mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
14061         lvregs = (guint32 *)mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
14062         lvregs_len = 0;
14063
14064         /* 
14065          * These arrays contain the first and last instructions accessing a given
14066          * variable.
14067          * Since we emit bblocks in the same order we process them here, and we
14068          * don't split live ranges, these will precisely describe the live range of
14069          * the variable, i.e. the instruction range where a valid value can be found
14070          * in the variables location.
14071          * The live range is computed using the liveness info computed by the liveness pass.
14072          * We can't use vmv->range, since that is an abstract live range, and we need
14073          * one which is instruction precise.
14074          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
14075          */
14076         /* FIXME: Only do this if debugging info is requested */
14077         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
14078         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
14079         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14080         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
14081         
14082         /* Add spill loads/stores */
14083         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
14084                 MonoInst *ins;
14085
14086                 if (cfg->verbose_level > 2)
14087                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
14088
14089                 /* Clear vreg_to_lvreg array */
14090                 for (i = 0; i < lvregs_len; i++)
14091                         vreg_to_lvreg [lvregs [i]] = 0;
14092                 lvregs_len = 0;
14093
14094                 cfg->cbb = bb;
14095                 MONO_BB_FOR_EACH_INS (bb, ins) {
14096                         const char *spec = INS_INFO (ins->opcode);
14097                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
14098                         gboolean store, no_lvreg;
14099                         int sregs [MONO_MAX_SRC_REGS];
14100
14101                         if (G_UNLIKELY (cfg->verbose_level > 2))
14102                                 mono_print_ins (ins);
14103
14104                         if (ins->opcode == OP_NOP)
14105                                 continue;
14106
14107                         /* 
14108                          * We handle LDADDR here as well, since it can only be decomposed
14109                          * when variable addresses are known.
14110                          */
14111                         if (ins->opcode == OP_LDADDR) {
14112                                 MonoInst *var = (MonoInst *)ins->inst_p0;
14113
14114                                 if (var->opcode == OP_VTARG_ADDR) {
14115                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
14116                                         MonoInst *vtaddr = var->inst_left;
14117                                         if (vtaddr->opcode == OP_REGVAR) {
14118                                                 ins->opcode = OP_MOVE;
14119                                                 ins->sreg1 = vtaddr->dreg;
14120                                         }
14121                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
14122                                                 ins->opcode = OP_LOAD_MEMBASE;
14123                                                 ins->inst_basereg = vtaddr->inst_basereg;
14124                                                 ins->inst_offset = vtaddr->inst_offset;
14125                                         } else
14126                                                 NOT_IMPLEMENTED;
14127                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
14128                                         /* gsharedvt arg passed by ref */
14129                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
14130
14131                                         ins->opcode = OP_LOAD_MEMBASE;
14132                                         ins->inst_basereg = var->inst_basereg;
14133                                         ins->inst_offset = var->inst_offset;
14134                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
14135                                         MonoInst *load, *load2, *load3;
14136                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
14137                                         int reg1, reg2, reg3;
14138                                         MonoInst *info_var = cfg->gsharedvt_info_var;
14139                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
14140
14141                                         /*
14142                                          * gsharedvt local.
14143                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
14144                                          */
14145
14146                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
14147
14148                                         g_assert (info_var);
14149                                         g_assert (locals_var);
14150
14151                                         /* Mark the instruction used to compute the locals var as used */
14152                                         cfg->gsharedvt_locals_var_ins = NULL;
14153
14154                                         /* Load the offset */
14155                                         if (info_var->opcode == OP_REGOFFSET) {
14156                                                 reg1 = alloc_ireg (cfg);
14157                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
14158                                         } else if (info_var->opcode == OP_REGVAR) {
14159                                                 load = NULL;
14160                                                 reg1 = info_var->dreg;
14161                                         } else {
14162                                                 g_assert_not_reached ();
14163                                         }
14164                                         reg2 = alloc_ireg (cfg);
14165                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, MONO_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
14166                                         /* Load the locals area address */
14167                                         reg3 = alloc_ireg (cfg);
14168                                         if (locals_var->opcode == OP_REGOFFSET) {
14169                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
14170                                         } else if (locals_var->opcode == OP_REGVAR) {
14171                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
14172                                         } else {
14173                                                 g_assert_not_reached ();
14174                                         }
14175                                         /* Compute the address */
14176                                         ins->opcode = OP_PADD;
14177                                         ins->sreg1 = reg3;
14178                                         ins->sreg2 = reg2;
14179
14180                                         mono_bblock_insert_before_ins (bb, ins, load3);
14181                                         mono_bblock_insert_before_ins (bb, load3, load2);
14182                                         if (load)
14183                                                 mono_bblock_insert_before_ins (bb, load2, load);
14184                                 } else {
14185                                         g_assert (var->opcode == OP_REGOFFSET);
14186
14187                                         ins->opcode = OP_ADD_IMM;
14188                                         ins->sreg1 = var->inst_basereg;
14189                                         ins->inst_imm = var->inst_offset;
14190                                 }
14191
14192                                 *need_local_opts = TRUE;
14193                                 spec = INS_INFO (ins->opcode);
14194                         }
14195
14196                         if (ins->opcode < MONO_CEE_LAST) {
14197                                 mono_print_ins (ins);
14198                                 g_assert_not_reached ();
14199                         }
14200
14201                         /*
14202                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
14203                          * src register.
14204                          * FIXME:
14205                          */
14206                         if (MONO_IS_STORE_MEMBASE (ins)) {
14207                                 tmp_reg = ins->dreg;
14208                                 ins->dreg = ins->sreg2;
14209                                 ins->sreg2 = tmp_reg;
14210                                 store = TRUE;
14211
14212                                 spec2 [MONO_INST_DEST] = ' ';
14213                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14214                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14215                                 spec2 [MONO_INST_SRC3] = ' ';
14216                                 spec = spec2;
14217                         } else if (MONO_IS_STORE_MEMINDEX (ins))
14218                                 g_assert_not_reached ();
14219                         else
14220                                 store = FALSE;
14221                         no_lvreg = FALSE;
14222
14223                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
14224                                 printf ("\t %.3s %d", spec, ins->dreg);
14225                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
14226                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
14227                                         printf (" %d", sregs [srcindex]);
14228                                 printf ("\n");
14229                         }
14230
14231                         /***************/
14232                         /*    DREG     */
14233                         /***************/
14234                         regtype = spec [MONO_INST_DEST];
14235                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
14236                         prev_dreg = -1;
14237
14238                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
14239                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
14240                                 MonoInst *store_ins;
14241                                 int store_opcode;
14242                                 MonoInst *def_ins = ins;
14243                                 int dreg = ins->dreg; /* The original vreg */
14244
14245                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
14246
14247                                 if (var->opcode == OP_REGVAR) {
14248                                         ins->dreg = var->dreg;
14249                                 } 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)) {
14250                                         /* 
14251                                          * Instead of emitting a load+store, use a _membase opcode.
14252                                          */
14253                                         g_assert (var->opcode == OP_REGOFFSET);
14254                                         if (ins->opcode == OP_MOVE) {
14255                                                 NULLIFY_INS (ins);
14256                                                 def_ins = NULL;
14257                                         } else {
14258                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
14259                                                 ins->inst_basereg = var->inst_basereg;
14260                                                 ins->inst_offset = var->inst_offset;
14261                                                 ins->dreg = -1;
14262                                         }
14263                                         spec = INS_INFO (ins->opcode);
14264                                 } else {
14265                                         guint32 lvreg;
14266
14267                                         g_assert (var->opcode == OP_REGOFFSET);
14268
14269                                         prev_dreg = ins->dreg;
14270
14271                                         /* Invalidate any previous lvreg for this vreg */
14272                                         vreg_to_lvreg [ins->dreg] = 0;
14273
14274                                         lvreg = 0;
14275
14276                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
14277                                                 regtype = 'l';
14278                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
14279                                         }
14280
14281                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
14282
14283 #if SIZEOF_REGISTER != 8
14284                                         if (regtype == 'l') {
14285                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
14286                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14287                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
14288                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
14289                                                 def_ins = store_ins;
14290                                         }
14291                                         else
14292 #endif
14293                                         {
14294                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
14295
14296                                                 /* Try to fuse the store into the instruction itself */
14297                                                 /* FIXME: Add more instructions */
14298                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
14299                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
14300                                                         ins->inst_imm = ins->inst_c0;
14301                                                         ins->inst_destbasereg = var->inst_basereg;
14302                                                         ins->inst_offset = var->inst_offset;
14303                                                         spec = INS_INFO (ins->opcode);
14304                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE) || (ins->opcode == OP_RMOVE))) {
14305                                                         ins->opcode = store_opcode;
14306                                                         ins->inst_destbasereg = var->inst_basereg;
14307                                                         ins->inst_offset = var->inst_offset;
14308
14309                                                         no_lvreg = TRUE;
14310
14311                                                         tmp_reg = ins->dreg;
14312                                                         ins->dreg = ins->sreg2;
14313                                                         ins->sreg2 = tmp_reg;
14314                                                         store = TRUE;
14315
14316                                                         spec2 [MONO_INST_DEST] = ' ';
14317                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
14318                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
14319                                                         spec2 [MONO_INST_SRC3] = ' ';
14320                                                         spec = spec2;
14321                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
14322                                                         // FIXME: The backends expect the base reg to be in inst_basereg
14323                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
14324                                                         ins->dreg = -1;
14325                                                         ins->inst_basereg = var->inst_basereg;
14326                                                         ins->inst_offset = var->inst_offset;
14327                                                         spec = INS_INFO (ins->opcode);
14328                                                 } else {
14329                                                         /* printf ("INS: "); mono_print_ins (ins); */
14330                                                         /* Create a store instruction */
14331                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
14332
14333                                                         /* Insert it after the instruction */
14334                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
14335
14336                                                         def_ins = store_ins;
14337
14338                                                         /* 
14339                                                          * We can't assign ins->dreg to var->dreg here, since the
14340                                                          * sregs could use it. So set a flag, and do it after
14341                                                          * the sregs.
14342                                                          */
14343                                                         if ((!cfg->backend->use_fpstack || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
14344                                                                 dest_has_lvreg = TRUE;
14345                                                 }
14346                                         }
14347                                 }
14348
14349                                 if (def_ins && !live_range_start [dreg]) {
14350                                         live_range_start [dreg] = def_ins;
14351                                         live_range_start_bb [dreg] = bb;
14352                                 }
14353
14354                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
14355                                         MonoInst *tmp;
14356
14357                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
14358                                         tmp->inst_c1 = dreg;
14359                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
14360                                 }
14361                         }
14362
14363                         /************/
14364                         /*  SREGS   */
14365                         /************/
14366                         num_sregs = mono_inst_get_src_registers (ins, sregs);
14367                         for (srcindex = 0; srcindex < 3; ++srcindex) {
14368                                 regtype = spec [MONO_INST_SRC1 + srcindex];
14369                                 sreg = sregs [srcindex];
14370
14371                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
14372                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
14373                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
14374                                         MonoInst *use_ins = ins;
14375                                         MonoInst *load_ins;
14376                                         guint32 load_opcode;
14377
14378                                         if (var->opcode == OP_REGVAR) {
14379                                                 sregs [srcindex] = var->dreg;
14380                                                 //mono_inst_set_src_registers (ins, sregs);
14381                                                 live_range_end [sreg] = use_ins;
14382                                                 live_range_end_bb [sreg] = bb;
14383
14384                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14385                                                         MonoInst *tmp;
14386
14387                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14388                                                         /* var->dreg is a hreg */
14389                                                         tmp->inst_c1 = sreg;
14390                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
14391                                                 }
14392
14393                                                 continue;
14394                                         }
14395
14396                                         g_assert (var->opcode == OP_REGOFFSET);
14397                                                 
14398                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
14399
14400                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
14401
14402                                         if (vreg_to_lvreg [sreg]) {
14403                                                 g_assert (vreg_to_lvreg [sreg] != -1);
14404
14405                                                 /* The variable is already loaded to an lvreg */
14406                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
14407                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
14408                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
14409                                                 //mono_inst_set_src_registers (ins, sregs);
14410                                                 continue;
14411                                         }
14412
14413                                         /* Try to fuse the load into the instruction */
14414                                         if ((srcindex == 0) && (op_to_op_src1_membase (cfg, load_opcode, ins->opcode) != -1)) {
14415                                                 ins->opcode = op_to_op_src1_membase (cfg, load_opcode, ins->opcode);
14416                                                 sregs [0] = var->inst_basereg;
14417                                                 //mono_inst_set_src_registers (ins, sregs);
14418                                                 ins->inst_offset = var->inst_offset;
14419                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (cfg, load_opcode, ins->opcode) != -1)) {
14420                                                 ins->opcode = op_to_op_src2_membase (cfg, load_opcode, ins->opcode);
14421                                                 sregs [1] = var->inst_basereg;
14422                                                 //mono_inst_set_src_registers (ins, sregs);
14423                                                 ins->inst_offset = var->inst_offset;
14424                                         } else {
14425                                                 if (MONO_IS_REAL_MOVE (ins)) {
14426                                                         ins->opcode = OP_NOP;
14427                                                         sreg = ins->dreg;
14428                                                 } else {
14429                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
14430
14431                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
14432
14433                                                         if ((!cfg->backend->use_fpstack || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
14434                                                                 if (var->dreg == prev_dreg) {
14435                                                                         /*
14436                                                                          * sreg refers to the value loaded by the load
14437                                                                          * emitted below, but we need to use ins->dreg
14438                                                                          * since it refers to the store emitted earlier.
14439                                                                          */
14440                                                                         sreg = ins->dreg;
14441                                                                 }
14442                                                                 g_assert (sreg != -1);
14443                                                                 vreg_to_lvreg [var->dreg] = sreg;
14444                                                                 g_assert (lvregs_len < 1024);
14445                                                                 lvregs [lvregs_len ++] = var->dreg;
14446                                                         }
14447                                                 }
14448
14449                                                 sregs [srcindex] = sreg;
14450                                                 //mono_inst_set_src_registers (ins, sregs);
14451
14452 #if SIZEOF_REGISTER != 8
14453                                                 if (regtype == 'l') {
14454                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
14455                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14456                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
14457                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14458                                                         use_ins = load_ins;
14459                                                 }
14460                                                 else
14461 #endif
14462                                                 {
14463 #if SIZEOF_REGISTER == 4
14464                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
14465 #endif
14466                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
14467                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
14468                                                         use_ins = load_ins;
14469                                                 }
14470                                         }
14471
14472                                         if (var->dreg < orig_next_vreg) {
14473                                                 live_range_end [var->dreg] = use_ins;
14474                                                 live_range_end_bb [var->dreg] = bb;
14475                                         }
14476
14477                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
14478                                                 MonoInst *tmp;
14479
14480                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
14481                                                 tmp->inst_c1 = var->dreg;
14482                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
14483                                         }
14484                                 }
14485                         }
14486                         mono_inst_set_src_registers (ins, sregs);
14487
14488                         if (dest_has_lvreg) {
14489                                 g_assert (ins->dreg != -1);
14490                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
14491                                 g_assert (lvregs_len < 1024);
14492                                 lvregs [lvregs_len ++] = prev_dreg;
14493                                 dest_has_lvreg = FALSE;
14494                         }
14495
14496                         if (store) {
14497                                 tmp_reg = ins->dreg;
14498                                 ins->dreg = ins->sreg2;
14499                                 ins->sreg2 = tmp_reg;
14500                         }
14501
14502                         if (MONO_IS_CALL (ins)) {
14503                                 /* Clear vreg_to_lvreg array */
14504                                 for (i = 0; i < lvregs_len; i++)
14505                                         vreg_to_lvreg [lvregs [i]] = 0;
14506                                 lvregs_len = 0;
14507                         } else if (ins->opcode == OP_NOP) {
14508                                 ins->dreg = -1;
14509                                 MONO_INST_NULLIFY_SREGS (ins);
14510                         }
14511
14512                         if (cfg->verbose_level > 2)
14513                                 mono_print_ins_index (1, ins);
14514                 }
14515
14516                 /* Extend the live range based on the liveness info */
14517                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
14518                         for (i = 0; i < cfg->num_varinfo; i ++) {
14519                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
14520
14521                                 if (vreg_is_volatile (cfg, vi->vreg))
14522                                         /* The liveness info is incomplete */
14523                                         continue;
14524
14525                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
14526                                         /* Live from at least the first ins of this bb */
14527                                         live_range_start [vi->vreg] = bb->code;
14528                                         live_range_start_bb [vi->vreg] = bb;
14529                                 }
14530
14531                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
14532                                         /* Live at least until the last ins of this bb */
14533                                         live_range_end [vi->vreg] = bb->last_ins;
14534                                         live_range_end_bb [vi->vreg] = bb;
14535                                 }
14536                         }
14537                 }
14538         }
14539         
14540         /*
14541          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
14542          * by storing the current native offset into MonoMethodVar->live_range_start/end.
14543          */
14544         if (cfg->backend->have_liverange_ops && cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
14545                 for (i = 0; i < cfg->num_varinfo; ++i) {
14546                         int vreg = MONO_VARINFO (cfg, i)->vreg;
14547                         MonoInst *ins;
14548
14549                         if (live_range_start [vreg]) {
14550                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
14551                                 ins->inst_c0 = i;
14552                                 ins->inst_c1 = vreg;
14553                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
14554                         }
14555                         if (live_range_end [vreg]) {
14556                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
14557                                 ins->inst_c0 = i;
14558                                 ins->inst_c1 = vreg;
14559                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
14560                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
14561                                 else
14562                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
14563                         }
14564                 }
14565         }
14566
14567         if (cfg->gsharedvt_locals_var_ins) {
14568                 /* Nullify if unused */
14569                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
14570                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
14571         }
14572
14573         g_free (live_range_start);
14574         g_free (live_range_end);
14575         g_free (live_range_start_bb);
14576         g_free (live_range_end_bb);
14577 }
14578
14579 /**
14580  * FIXME:
14581  * - use 'iadd' instead of 'int_add'
14582  * - handling ovf opcodes: decompose in method_to_ir.
14583  * - unify iregs/fregs
14584  *   -> partly done, the missing parts are:
14585  *   - a more complete unification would involve unifying the hregs as well, so
14586  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
14587  *     would no longer map to the machine hregs, so the code generators would need to
14588  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
14589  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
14590  *     fp/non-fp branches speeds it up by about 15%.
14591  * - use sext/zext opcodes instead of shifts
14592  * - add OP_ICALL
14593  * - get rid of TEMPLOADs if possible and use vregs instead
14594  * - clean up usage of OP_P/OP_ opcodes
14595  * - cleanup usage of DUMMY_USE
14596  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
14597  *   stack
14598  * - set the stack type and allocate a dreg in the EMIT_NEW macros
14599  * - get rid of all the <foo>2 stuff when the new JIT is ready.
14600  * - make sure handle_stack_args () is called before the branch is emitted
14601  * - when the new IR is done, get rid of all unused stuff
14602  * - COMPARE/BEQ as separate instructions or unify them ?
14603  *   - keeping them separate allows specialized compare instructions like
14604  *     compare_imm, compare_membase
14605  *   - most back ends unify fp compare+branch, fp compare+ceq
14606  * - integrate mono_save_args into inline_method
14607  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
14608  * - handle long shift opts on 32 bit platforms somehow: they require 
14609  *   3 sregs (2 for arg1 and 1 for arg2)
14610  * - make byref a 'normal' type.
14611  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
14612  *   variable if needed.
14613  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
14614  *   like inline_method.
14615  * - remove inlining restrictions
14616  * - fix LNEG and enable cfold of INEG
14617  * - generalize x86 optimizations like ldelema as a peephole optimization
14618  * - add store_mem_imm for amd64
14619  * - optimize the loading of the interruption flag in the managed->native wrappers
14620  * - avoid special handling of OP_NOP in passes
14621  * - move code inserting instructions into one function/macro.
14622  * - try a coalescing phase after liveness analysis
14623  * - add float -> vreg conversion + local optimizations on !x86
14624  * - figure out how to handle decomposed branches during optimizations, ie.
14625  *   compare+branch, op_jump_table+op_br etc.
14626  * - promote RuntimeXHandles to vregs
14627  * - vtype cleanups:
14628  *   - add a NEW_VARLOADA_VREG macro
14629  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
14630  *   accessing vtype fields.
14631  * - get rid of I8CONST on 64 bit platforms
14632  * - dealing with the increase in code size due to branches created during opcode
14633  *   decomposition:
14634  *   - use extended basic blocks
14635  *     - all parts of the JIT
14636  *     - handle_global_vregs () && local regalloc
14637  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
14638  * - sources of increase in code size:
14639  *   - vtypes
14640  *   - long compares
14641  *   - isinst and castclass
14642  *   - lvregs not allocated to global registers even if used multiple times
14643  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
14644  *   meaningful.
14645  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
14646  * - add all micro optimizations from the old JIT
14647  * - put tree optimizations into the deadce pass
14648  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
14649  *   specific function.
14650  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
14651  *   fcompare + branchCC.
14652  * - create a helper function for allocating a stack slot, taking into account 
14653  *   MONO_CFG_HAS_SPILLUP.
14654  * - merge r68207.
14655  * - merge the ia64 switch changes.
14656  * - optimize mono_regstate2_alloc_int/float.
14657  * - fix the pessimistic handling of variables accessed in exception handler blocks.
14658  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
14659  *   parts of the tree could be separated by other instructions, killing the tree
14660  *   arguments, or stores killing loads etc. Also, should we fold loads into other
14661  *   instructions if the result of the load is used multiple times ?
14662  * - make the REM_IMM optimization in mini-x86.c arch-independent.
14663  * - LAST MERGE: 108395.
14664  * - when returning vtypes in registers, generate IR and append it to the end of the
14665  *   last bb instead of doing it in the epilog.
14666  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
14667  */
14668
14669 /*
14670
14671 NOTES
14672 -----
14673
14674 - When to decompose opcodes:
14675   - earlier: this makes some optimizations hard to implement, since the low level IR
14676   no longer contains the neccessary information. But it is easier to do.
14677   - later: harder to implement, enables more optimizations.
14678 - Branches inside bblocks:
14679   - created when decomposing complex opcodes. 
14680     - branches to another bblock: harmless, but not tracked by the branch 
14681       optimizations, so need to branch to a label at the start of the bblock.
14682     - branches to inside the same bblock: very problematic, trips up the local
14683       reg allocator. Can be fixed by spitting the current bblock, but that is a
14684       complex operation, since some local vregs can become global vregs etc.
14685 - Local/global vregs:
14686   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
14687     local register allocator.
14688   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
14689     structure, created by mono_create_var (). Assigned to hregs or the stack by
14690     the global register allocator.
14691 - When to do optimizations like alu->alu_imm:
14692   - earlier -> saves work later on since the IR will be smaller/simpler
14693   - later -> can work on more instructions
14694 - Handling of valuetypes:
14695   - When a vtype is pushed on the stack, a new temporary is created, an 
14696     instruction computing its address (LDADDR) is emitted and pushed on
14697     the stack. Need to optimize cases when the vtype is used immediately as in
14698     argument passing, stloc etc.
14699 - Instead of the to_end stuff in the old JIT, simply call the function handling
14700   the values on the stack before emitting the last instruction of the bb.
14701 */
14702
14703 #endif /* DISABLE_JIT */