SqlBulkCopy Implementation
[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
37 #include <mono/metadata/assembly.h>
38 #include <mono/metadata/attrdefs.h>
39 #include <mono/metadata/loader.h>
40 #include <mono/metadata/tabledefs.h>
41 #include <mono/metadata/class.h>
42 #include <mono/metadata/object.h>
43 #include <mono/metadata/exception.h>
44 #include <mono/metadata/opcodes.h>
45 #include <mono/metadata/mono-endian.h>
46 #include <mono/metadata/tokentype.h>
47 #include <mono/metadata/tabledefs.h>
48 #include <mono/metadata/marshal.h>
49 #include <mono/metadata/debug-helpers.h>
50 #include <mono/metadata/mono-debug.h>
51 #include <mono/metadata/gc-internal.h>
52 #include <mono/metadata/security-manager.h>
53 #include <mono/metadata/threads-types.h>
54 #include <mono/metadata/security-core-clr.h>
55 #include <mono/metadata/monitor.h>
56 #include <mono/metadata/profiler-private.h>
57 #include <mono/metadata/profiler.h>
58 #include <mono/metadata/debug-mono-symfile.h>
59 #include <mono/utils/mono-compiler.h>
60 #include <mono/utils/mono-memory-model.h>
61 #include <mono/metadata/mono-basic-block.h>
62
63 #include "mini.h"
64 #include "trace.h"
65
66 #include "ir-emit.h"
67
68 #include "jit-icalls.h"
69 #include "jit.h"
70 #include "debugger-agent.h"
71
72 #define BRANCH_COST 10
73 #define INLINE_LENGTH_LIMIT 20
74 #define INLINE_FAILURE(msg) do {                                                                        \
75         if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE)) { \
76                 if (cfg->verbose_level >= 2)                                                                    \
77                         printf ("inline failed: %s\n", msg);                                            \
78                 goto inline_failure;                                                                                    \
79         } \
80         } while (0)
81 #define CHECK_CFG_EXCEPTION do {\
82                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
83                         goto exception_exit;\
84         } while (0)
85 #define METHOD_ACCESS_FAILURE do {      \
86                 char *method_fname = mono_method_full_name (method, TRUE);      \
87                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
88                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);             \
89                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
90                 g_free (method_fname);  \
91                 g_free (cil_method_fname);      \
92                 goto exception_exit;    \
93         } while (0)
94 #define FIELD_ACCESS_FAILURE do {       \
95                 char *method_fname = mono_method_full_name (method, TRUE);      \
96                 char *field_fname = mono_field_full_name (field);       \
97                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);              \
98                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
99                 g_free (method_fname);  \
100                 g_free (field_fname);   \
101                 goto exception_exit;    \
102         } while (0)
103 #define GENERIC_SHARING_FAILURE(opcode) do {            \
104                 if (cfg->generic_sharing_context) {     \
105             if (cfg->verbose_level > 2) \
106                             printf ("sharing failed for method %s.%s.%s/%d opcode %s line %d\n", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __LINE__); \
107                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
108                         goto exception_exit;    \
109                 }                       \
110         } while (0)
111 #define GSHAREDVT_FAILURE(opcode) do {          \
112         if (cfg->gsharedvt) {                                                                                           \
113                 cfg->exception_message = g_strdup_printf ("gsharedvt failed for method %s.%s.%s/%d opcode %s %s:%d", method->klass->name_space, method->klass->name, method->name, method->signature->param_count, mono_opcode_name ((opcode)), __FILE__, __LINE__); \
114                 if (cfg->verbose_level >= 2)                                                                    \
115                         printf ("%s\n", cfg->exception_message); \
116                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
117                 goto exception_exit;                                                                                    \
118         }                                                                                                                                       \
119         } while (0)
120 #define OUT_OF_MEMORY_FAILURE do {      \
121                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
122                 goto exception_exit;    \
123         } while (0)
124 /* Determine whenever 'ins' represents a load of the 'this' argument */
125 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
126
127 static int ldind_to_load_membase (int opcode);
128 static int stind_to_store_membase (int opcode);
129
130 int mono_op_to_op_imm (int opcode);
131 int mono_op_to_op_imm_noemul (int opcode);
132
133 MONO_API MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
134
135 /* helper methods signatures */
136 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
137 static MonoMethodSignature *helper_sig_domain_get = NULL;
138 static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
139 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
140 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
141 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
142 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
143
144 /*
145  * Instruction metadata
146  */
147 #ifdef MINI_OP
148 #undef MINI_OP
149 #endif
150 #ifdef MINI_OP3
151 #undef MINI_OP3
152 #endif
153 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
154 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
155 #define NONE ' '
156 #define IREG 'i'
157 #define FREG 'f'
158 #define VREG 'v'
159 #define XREG 'x'
160 #if SIZEOF_REGISTER == 8 && SIZEOF_REGISTER == SIZEOF_VOID_P
161 #define LREG IREG
162 #else
163 #define LREG 'l'
164 #endif
165 /* keep in sync with the enum in mini.h */
166 const char
167 ins_info[] = {
168 #include "mini-ops.h"
169 };
170 #undef MINI_OP
171 #undef MINI_OP3
172
173 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
174 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
175 /* 
176  * This should contain the index of the last sreg + 1. This is not the same
177  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
178  */
179 const gint8 ins_sreg_counts[] = {
180 #include "mini-ops.h"
181 };
182 #undef MINI_OP
183 #undef MINI_OP3
184
185 #define MONO_INIT_VARINFO(vi,id) do { \
186         (vi)->range.first_use.pos.bid = 0xffff; \
187         (vi)->reg = -1; \
188         (vi)->idx = (id); \
189 } while (0)
190
191 void
192 mono_inst_set_src_registers (MonoInst *ins, int *regs)
193 {
194         ins->sreg1 = regs [0];
195         ins->sreg2 = regs [1];
196         ins->sreg3 = regs [2];
197 }
198
199 guint32
200 mono_alloc_ireg (MonoCompile *cfg)
201 {
202         return alloc_ireg (cfg);
203 }
204
205 guint32
206 mono_alloc_freg (MonoCompile *cfg)
207 {
208         return alloc_freg (cfg);
209 }
210
211 guint32
212 mono_alloc_preg (MonoCompile *cfg)
213 {
214         return alloc_preg (cfg);
215 }
216
217 guint32
218 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
219 {
220         return alloc_dreg (cfg, stack_type);
221 }
222
223 /*
224  * mono_alloc_ireg_ref:
225  *
226  *   Allocate an IREG, and mark it as holding a GC ref.
227  */
228 guint32
229 mono_alloc_ireg_ref (MonoCompile *cfg)
230 {
231         return alloc_ireg_ref (cfg);
232 }
233
234 /*
235  * mono_alloc_ireg_mp:
236  *
237  *   Allocate an IREG, and mark it as holding a managed pointer.
238  */
239 guint32
240 mono_alloc_ireg_mp (MonoCompile *cfg)
241 {
242         return alloc_ireg_mp (cfg);
243 }
244
245 /*
246  * mono_alloc_ireg_copy:
247  *
248  *   Allocate an IREG with the same GC type as VREG.
249  */
250 guint32
251 mono_alloc_ireg_copy (MonoCompile *cfg, guint32 vreg)
252 {
253         if (vreg_is_ref (cfg, vreg))
254                 return alloc_ireg_ref (cfg);
255         else if (vreg_is_mp (cfg, vreg))
256                 return alloc_ireg_mp (cfg);
257         else
258                 return alloc_ireg (cfg);
259 }
260
261 guint
262 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
263 {
264         if (type->byref)
265                 return OP_MOVE;
266
267 handle_enum:
268         switch (type->type) {
269         case MONO_TYPE_I1:
270         case MONO_TYPE_U1:
271         case MONO_TYPE_BOOLEAN:
272                 return OP_MOVE;
273         case MONO_TYPE_I2:
274         case MONO_TYPE_U2:
275         case MONO_TYPE_CHAR:
276                 return OP_MOVE;
277         case MONO_TYPE_I4:
278         case MONO_TYPE_U4:
279                 return OP_MOVE;
280         case MONO_TYPE_I:
281         case MONO_TYPE_U:
282         case MONO_TYPE_PTR:
283         case MONO_TYPE_FNPTR:
284                 return OP_MOVE;
285         case MONO_TYPE_CLASS:
286         case MONO_TYPE_STRING:
287         case MONO_TYPE_OBJECT:
288         case MONO_TYPE_SZARRAY:
289         case MONO_TYPE_ARRAY:    
290                 return OP_MOVE;
291         case MONO_TYPE_I8:
292         case MONO_TYPE_U8:
293 #if SIZEOF_REGISTER == 8
294                 return OP_MOVE;
295 #else
296                 return OP_LMOVE;
297 #endif
298         case MONO_TYPE_R4:
299                 return OP_FMOVE;
300         case MONO_TYPE_R8:
301                 return OP_FMOVE;
302         case MONO_TYPE_VALUETYPE:
303                 if (type->data.klass->enumtype) {
304                         type = mono_class_enum_basetype (type->data.klass);
305                         goto handle_enum;
306                 }
307                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
308                         return OP_XMOVE;
309                 return OP_VMOVE;
310         case MONO_TYPE_TYPEDBYREF:
311                 return OP_VMOVE;
312         case MONO_TYPE_GENERICINST:
313                 type = &type->data.generic_class->container_class->byval_arg;
314                 goto handle_enum;
315         case MONO_TYPE_VAR:
316         case MONO_TYPE_MVAR:
317                 g_assert (cfg->generic_sharing_context);
318                 if (mini_type_var_is_vt (cfg, type))
319                         return OP_VMOVE;
320                 else
321                         return OP_MOVE;
322         default:
323                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
324         }
325         return -1;
326 }
327
328 void
329 mono_print_bb (MonoBasicBlock *bb, const char *msg)
330 {
331         int i;
332         MonoInst *tree;
333
334         printf ("\n%s %d: [IN: ", msg, bb->block_num);
335         for (i = 0; i < bb->in_count; ++i)
336                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
337         printf (", OUT: ");
338         for (i = 0; i < bb->out_count; ++i)
339                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
340         printf (" ]\n");
341         for (tree = bb->code; tree; tree = tree->next)
342                 mono_print_ins_index (-1, tree);
343 }
344
345 void
346 mono_create_helper_signatures (void)
347 {
348         helper_sig_domain_get = mono_create_icall_signature ("ptr");
349         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
350         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
351         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
352         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
353         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
354         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
355 }
356
357 /*
358  * When using gsharedvt, some instatiations might be verifiable, and some might be not. i.e. 
359  * foo<T> (int i) { ldarg.0; box T; }
360  */
361 #define UNVERIFIED do { \
362         if (cfg->gsharedvt) { \
363                 if (cfg->verbose_level > 2)                                                                     \
364                         printf ("gsharedvt method failed to verify, falling back to instantiation.\n"); \
365                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
366                 goto exception_exit;                                                                                    \
367         }                                                                                                                                       \
368         if (mini_get_debug_options ()->break_on_unverified) \
369                 G_BREAKPOINT (); \
370         else \
371                 goto unverified; \
372 } while (0)
373
374 #define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
375
376 #define TYPE_LOAD_ERROR(klass) do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else { cfg->exception_ptr = klass; goto load_error; } } while (0)
377
378 #define GET_BBLOCK(cfg,tblock,ip) do {  \
379                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
380                 if (!(tblock)) {        \
381                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
382             NEW_BBLOCK (cfg, (tblock)); \
383                         (tblock)->cil_code = (ip);      \
384                         ADD_BBLOCK (cfg, (tblock));     \
385                 } \
386         } while (0)
387
388 #if defined(TARGET_X86) || defined(TARGET_AMD64)
389 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
390                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
391                 (dest)->dreg = alloc_ireg_mp ((cfg)); \
392                 (dest)->sreg1 = (sr1); \
393                 (dest)->sreg2 = (sr2); \
394                 (dest)->inst_imm = (imm); \
395                 (dest)->backend.shift_amount = (shift); \
396                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
397         } while (0)
398 #endif
399
400 #if SIZEOF_REGISTER == 8
401 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
402                 /* FIXME: Need to add many more cases */ \
403                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
404                         MonoInst *widen; \
405                         int dr = alloc_preg (cfg); \
406                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
407                         (ins)->sreg2 = widen->dreg; \
408                 } \
409         } while (0)
410 #else
411 #define ADD_WIDEN_OP(ins, arg1, arg2)
412 #endif
413
414 #define ADD_BINOP(op) do {      \
415                 MONO_INST_NEW (cfg, ins, (op)); \
416                 sp -= 2;        \
417                 ins->sreg1 = sp [0]->dreg;      \
418                 ins->sreg2 = sp [1]->dreg;      \
419                 type_from_op (ins, sp [0], sp [1]);     \
420                 CHECK_TYPE (ins);       \
421                 /* Have to insert a widening op */               \
422         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
423         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
424         MONO_ADD_INS ((cfg)->cbb, (ins)); \
425         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
426         } while (0)
427
428 #define ADD_UNOP(op) do {       \
429                 MONO_INST_NEW (cfg, ins, (op)); \
430                 sp--;   \
431                 ins->sreg1 = sp [0]->dreg;      \
432                 type_from_op (ins, sp [0], NULL);       \
433                 CHECK_TYPE (ins);       \
434         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
435         MONO_ADD_INS ((cfg)->cbb, (ins)); \
436                 *sp++ = mono_decompose_opcode (cfg, ins); \
437         } while (0)
438
439 #define ADD_BINCOND(next_block) do {    \
440                 MonoInst *cmp;  \
441                 sp -= 2; \
442                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
443                 cmp->sreg1 = sp [0]->dreg;      \
444                 cmp->sreg2 = sp [1]->dreg;      \
445                 type_from_op (cmp, sp [0], sp [1]);     \
446                 CHECK_TYPE (cmp);       \
447                 type_from_op (ins, sp [0], sp [1]);     \
448                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
449                 GET_BBLOCK (cfg, tblock, target);               \
450                 link_bblock (cfg, bblock, tblock);      \
451                 ins->inst_true_bb = tblock;     \
452                 if ((next_block)) {     \
453                         link_bblock (cfg, bblock, (next_block));        \
454                         ins->inst_false_bb = (next_block);      \
455                         start_new_bblock = 1;   \
456                 } else {        \
457                         GET_BBLOCK (cfg, tblock, ip);           \
458                         link_bblock (cfg, bblock, tblock);      \
459                         ins->inst_false_bb = tblock;    \
460                         start_new_bblock = 2;   \
461                 }       \
462                 if (sp != stack_start) {                                                                        \
463                     handle_stack_args (cfg, stack_start, sp - stack_start); \
464                         CHECK_UNVERIFIABLE (cfg); \
465                 } \
466         MONO_ADD_INS (bblock, cmp); \
467                 MONO_ADD_INS (bblock, ins);     \
468         } while (0)
469
470 /* *
471  * link_bblock: Links two basic blocks
472  *
473  * links two basic blocks in the control flow graph, the 'from'
474  * argument is the starting block and the 'to' argument is the block
475  * the control flow ends to after 'from'.
476  */
477 static void
478 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
479 {
480         MonoBasicBlock **newa;
481         int i, found;
482
483 #if 0
484         if (from->cil_code) {
485                 if (to->cil_code)
486                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
487                 else
488                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
489         } else {
490                 if (to->cil_code)
491                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
492                 else
493                         printf ("edge from entry to exit\n");
494         }
495 #endif
496
497         found = FALSE;
498         for (i = 0; i < from->out_count; ++i) {
499                 if (to == from->out_bb [i]) {
500                         found = TRUE;
501                         break;
502                 }
503         }
504         if (!found) {
505                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
506                 for (i = 0; i < from->out_count; ++i) {
507                         newa [i] = from->out_bb [i];
508                 }
509                 newa [i] = to;
510                 from->out_count++;
511                 from->out_bb = newa;
512         }
513
514         found = FALSE;
515         for (i = 0; i < to->in_count; ++i) {
516                 if (from == to->in_bb [i]) {
517                         found = TRUE;
518                         break;
519                 }
520         }
521         if (!found) {
522                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
523                 for (i = 0; i < to->in_count; ++i) {
524                         newa [i] = to->in_bb [i];
525                 }
526                 newa [i] = from;
527                 to->in_count++;
528                 to->in_bb = newa;
529         }
530 }
531
532 void
533 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
534 {
535         link_bblock (cfg, from, to);
536 }
537
538 /**
539  * mono_find_block_region:
540  *
541  *   We mark each basic block with a region ID. We use that to avoid BB
542  *   optimizations when blocks are in different regions.
543  *
544  * Returns:
545  *   A region token that encodes where this region is, and information
546  *   about the clause owner for this block.
547  *
548  *   The region encodes the try/catch/filter clause that owns this block
549  *   as well as the type.  -1 is a special value that represents a block
550  *   that is in none of try/catch/filter.
551  */
552 static int
553 mono_find_block_region (MonoCompile *cfg, int offset)
554 {
555         MonoMethodHeader *header = cfg->header;
556         MonoExceptionClause *clause;
557         int i;
558
559         for (i = 0; i < header->num_clauses; ++i) {
560                 clause = &header->clauses [i];
561                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
562                     (offset < (clause->handler_offset)))
563                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
564                            
565                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
566                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
567                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
568                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
569                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
570                         else
571                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
572                 }
573
574                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
575                         return ((i + 1) << 8) | clause->flags;
576         }
577
578         return -1;
579 }
580
581 static GList*
582 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
583 {
584         MonoMethodHeader *header = cfg->header;
585         MonoExceptionClause *clause;
586         int i;
587         GList *res = NULL;
588
589         for (i = 0; i < header->num_clauses; ++i) {
590                 clause = &header->clauses [i];
591                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
592                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
593                         if (clause->flags == type)
594                                 res = g_list_append (res, clause);
595                 }
596         }
597         return res;
598 }
599
600 static void
601 mono_create_spvar_for_region (MonoCompile *cfg, int region)
602 {
603         MonoInst *var;
604
605         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
606         if (var)
607                 return;
608
609         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
610         /* prevent it from being register allocated */
611         var->flags |= MONO_INST_INDIRECT;
612
613         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
614 }
615
616 MonoInst *
617 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
618 {
619         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
620 }
621
622 static MonoInst*
623 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
624 {
625         MonoInst *var;
626
627         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
628         if (var)
629                 return var;
630
631         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
632         /* prevent it from being register allocated */
633         var->flags |= MONO_INST_INDIRECT;
634
635         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
636
637         return var;
638 }
639
640 /*
641  * Returns the type used in the eval stack when @type is loaded.
642  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
643  */
644 void
645 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
646 {
647         MonoClass *klass;
648
649         inst->klass = klass = mono_class_from_mono_type (type);
650         if (type->byref) {
651                 inst->type = STACK_MP;
652                 return;
653         }
654
655 handle_enum:
656         switch (type->type) {
657         case MONO_TYPE_VOID:
658                 inst->type = STACK_INV;
659                 return;
660         case MONO_TYPE_I1:
661         case MONO_TYPE_U1:
662         case MONO_TYPE_BOOLEAN:
663         case MONO_TYPE_I2:
664         case MONO_TYPE_U2:
665         case MONO_TYPE_CHAR:
666         case MONO_TYPE_I4:
667         case MONO_TYPE_U4:
668                 inst->type = STACK_I4;
669                 return;
670         case MONO_TYPE_I:
671         case MONO_TYPE_U:
672         case MONO_TYPE_PTR:
673         case MONO_TYPE_FNPTR:
674                 inst->type = STACK_PTR;
675                 return;
676         case MONO_TYPE_CLASS:
677         case MONO_TYPE_STRING:
678         case MONO_TYPE_OBJECT:
679         case MONO_TYPE_SZARRAY:
680         case MONO_TYPE_ARRAY:    
681                 inst->type = STACK_OBJ;
682                 return;
683         case MONO_TYPE_I8:
684         case MONO_TYPE_U8:
685                 inst->type = STACK_I8;
686                 return;
687         case MONO_TYPE_R4:
688         case MONO_TYPE_R8:
689                 inst->type = STACK_R8;
690                 return;
691         case MONO_TYPE_VALUETYPE:
692                 if (type->data.klass->enumtype) {
693                         type = mono_class_enum_basetype (type->data.klass);
694                         goto handle_enum;
695                 } else {
696                         inst->klass = klass;
697                         inst->type = STACK_VTYPE;
698                         return;
699                 }
700         case MONO_TYPE_TYPEDBYREF:
701                 inst->klass = mono_defaults.typed_reference_class;
702                 inst->type = STACK_VTYPE;
703                 return;
704         case MONO_TYPE_GENERICINST:
705                 type = &type->data.generic_class->container_class->byval_arg;
706                 goto handle_enum;
707         case MONO_TYPE_VAR:
708         case MONO_TYPE_MVAR:
709                 g_assert (cfg->generic_sharing_context);
710                 if (mini_is_gsharedvt_type (cfg, type)) {
711                         g_assert (cfg->gsharedvt);
712                         inst->type = STACK_VTYPE;
713                 } else {
714                         inst->type = STACK_OBJ;
715                 }
716                 return;
717         default:
718                 g_error ("unknown type 0x%02x in eval stack type", type->type);
719         }
720 }
721
722 /*
723  * The following tables are used to quickly validate the IL code in type_from_op ().
724  */
725 static const char
726 bin_num_table [STACK_MAX] [STACK_MAX] = {
727         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
728         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
729         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
730         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
731         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
732         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
733         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
734         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
735 };
736
737 static const char 
738 neg_table [] = {
739         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
740 };
741
742 /* reduce the size of this table */
743 static const char
744 bin_int_table [STACK_MAX] [STACK_MAX] = {
745         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
746         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
747         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
748         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
749         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
750         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
751         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
752         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
753 };
754
755 static const char
756 bin_comp_table [STACK_MAX] [STACK_MAX] = {
757 /*      Inv i  L  p  F  &  O  vt */
758         {0},
759         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
760         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
761         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
762         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
763         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
764         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
765         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
766 };
767
768 /* reduce the size of this table */
769 static const char
770 shift_table [STACK_MAX] [STACK_MAX] = {
771         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
772         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
773         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
774         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
775         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
776         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
777         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
778         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
779 };
780
781 /*
782  * Tables to map from the non-specific opcode to the matching
783  * type-specific opcode.
784  */
785 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
786 static const guint16
787 binops_op_map [STACK_MAX] = {
788         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
789 };
790
791 /* handles from CEE_NEG to CEE_CONV_U8 */
792 static const guint16
793 unops_op_map [STACK_MAX] = {
794         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
795 };
796
797 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
798 static const guint16
799 ovfops_op_map [STACK_MAX] = {
800         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
801 };
802
803 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
804 static const guint16
805 ovf2ops_op_map [STACK_MAX] = {
806         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
807 };
808
809 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
810 static const guint16
811 ovf3ops_op_map [STACK_MAX] = {
812         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
813 };
814
815 /* handles from CEE_BEQ to CEE_BLT_UN */
816 static const guint16
817 beqops_op_map [STACK_MAX] = {
818         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
819 };
820
821 /* handles from CEE_CEQ to CEE_CLT_UN */
822 static const guint16
823 ceqops_op_map [STACK_MAX] = {
824         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
825 };
826
827 /*
828  * Sets ins->type (the type on the eval stack) according to the
829  * type of the opcode and the arguments to it.
830  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
831  *
832  * FIXME: this function sets ins->type unconditionally in some cases, but
833  * it should set it to invalid for some types (a conv.x on an object)
834  */
835 static void
836 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
837
838         switch (ins->opcode) {
839         /* binops */
840         case CEE_ADD:
841         case CEE_SUB:
842         case CEE_MUL:
843         case CEE_DIV:
844         case CEE_REM:
845                 /* FIXME: check unverifiable args for STACK_MP */
846                 ins->type = bin_num_table [src1->type] [src2->type];
847                 ins->opcode += binops_op_map [ins->type];
848                 break;
849         case CEE_DIV_UN:
850         case CEE_REM_UN:
851         case CEE_AND:
852         case CEE_OR:
853         case CEE_XOR:
854                 ins->type = bin_int_table [src1->type] [src2->type];
855                 ins->opcode += binops_op_map [ins->type];
856                 break;
857         case CEE_SHL:
858         case CEE_SHR:
859         case CEE_SHR_UN:
860                 ins->type = shift_table [src1->type] [src2->type];
861                 ins->opcode += binops_op_map [ins->type];
862                 break;
863         case OP_COMPARE:
864         case OP_LCOMPARE:
865         case OP_ICOMPARE:
866                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
867                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
868                         ins->opcode = OP_LCOMPARE;
869                 else if (src1->type == STACK_R8)
870                         ins->opcode = OP_FCOMPARE;
871                 else
872                         ins->opcode = OP_ICOMPARE;
873                 break;
874         case OP_ICOMPARE_IMM:
875                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
876                 if ((src1->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
877                         ins->opcode = OP_LCOMPARE_IMM;          
878                 break;
879         case CEE_BEQ:
880         case CEE_BGE:
881         case CEE_BGT:
882         case CEE_BLE:
883         case CEE_BLT:
884         case CEE_BNE_UN:
885         case CEE_BGE_UN:
886         case CEE_BGT_UN:
887         case CEE_BLE_UN:
888         case CEE_BLT_UN:
889                 ins->opcode += beqops_op_map [src1->type];
890                 break;
891         case OP_CEQ:
892                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
893                 ins->opcode += ceqops_op_map [src1->type];
894                 break;
895         case OP_CGT:
896         case OP_CGT_UN:
897         case OP_CLT:
898         case OP_CLT_UN:
899                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
900                 ins->opcode += ceqops_op_map [src1->type];
901                 break;
902         /* unops */
903         case CEE_NEG:
904                 ins->type = neg_table [src1->type];
905                 ins->opcode += unops_op_map [ins->type];
906                 break;
907         case CEE_NOT:
908                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
909                         ins->type = src1->type;
910                 else
911                         ins->type = STACK_INV;
912                 ins->opcode += unops_op_map [ins->type];
913                 break;
914         case CEE_CONV_I1:
915         case CEE_CONV_I2:
916         case CEE_CONV_I4:
917         case CEE_CONV_U4:
918                 ins->type = STACK_I4;
919                 ins->opcode += unops_op_map [src1->type];
920                 break;
921         case CEE_CONV_R_UN:
922                 ins->type = STACK_R8;
923                 switch (src1->type) {
924                 case STACK_I4:
925                 case STACK_PTR:
926                         ins->opcode = OP_ICONV_TO_R_UN;
927                         break;
928                 case STACK_I8:
929                         ins->opcode = OP_LCONV_TO_R_UN; 
930                         break;
931                 }
932                 break;
933         case CEE_CONV_OVF_I1:
934         case CEE_CONV_OVF_U1:
935         case CEE_CONV_OVF_I2:
936         case CEE_CONV_OVF_U2:
937         case CEE_CONV_OVF_I4:
938         case CEE_CONV_OVF_U4:
939                 ins->type = STACK_I4;
940                 ins->opcode += ovf3ops_op_map [src1->type];
941                 break;
942         case CEE_CONV_OVF_I_UN:
943         case CEE_CONV_OVF_U_UN:
944                 ins->type = STACK_PTR;
945                 ins->opcode += ovf2ops_op_map [src1->type];
946                 break;
947         case CEE_CONV_OVF_I1_UN:
948         case CEE_CONV_OVF_I2_UN:
949         case CEE_CONV_OVF_I4_UN:
950         case CEE_CONV_OVF_U1_UN:
951         case CEE_CONV_OVF_U2_UN:
952         case CEE_CONV_OVF_U4_UN:
953                 ins->type = STACK_I4;
954                 ins->opcode += ovf2ops_op_map [src1->type];
955                 break;
956         case CEE_CONV_U:
957                 ins->type = STACK_PTR;
958                 switch (src1->type) {
959                 case STACK_I4:
960                         ins->opcode = OP_ICONV_TO_U;
961                         break;
962                 case STACK_PTR:
963                 case STACK_MP:
964 #if SIZEOF_VOID_P == 8
965                         ins->opcode = OP_LCONV_TO_U;
966 #else
967                         ins->opcode = OP_MOVE;
968 #endif
969                         break;
970                 case STACK_I8:
971                         ins->opcode = OP_LCONV_TO_U;
972                         break;
973                 case STACK_R8:
974                         ins->opcode = OP_FCONV_TO_U;
975                         break;
976                 }
977                 break;
978         case CEE_CONV_I8:
979         case CEE_CONV_U8:
980                 ins->type = STACK_I8;
981                 ins->opcode += unops_op_map [src1->type];
982                 break;
983         case CEE_CONV_OVF_I8:
984         case CEE_CONV_OVF_U8:
985                 ins->type = STACK_I8;
986                 ins->opcode += ovf3ops_op_map [src1->type];
987                 break;
988         case CEE_CONV_OVF_U8_UN:
989         case CEE_CONV_OVF_I8_UN:
990                 ins->type = STACK_I8;
991                 ins->opcode += ovf2ops_op_map [src1->type];
992                 break;
993         case CEE_CONV_R4:
994         case CEE_CONV_R8:
995                 ins->type = STACK_R8;
996                 ins->opcode += unops_op_map [src1->type];
997                 break;
998         case OP_CKFINITE:
999                 ins->type = STACK_R8;           
1000                 break;
1001         case CEE_CONV_U2:
1002         case CEE_CONV_U1:
1003                 ins->type = STACK_I4;
1004                 ins->opcode += ovfops_op_map [src1->type];
1005                 break;
1006         case CEE_CONV_I:
1007         case CEE_CONV_OVF_I:
1008         case CEE_CONV_OVF_U:
1009                 ins->type = STACK_PTR;
1010                 ins->opcode += ovfops_op_map [src1->type];
1011                 break;
1012         case CEE_ADD_OVF:
1013         case CEE_ADD_OVF_UN:
1014         case CEE_MUL_OVF:
1015         case CEE_MUL_OVF_UN:
1016         case CEE_SUB_OVF:
1017         case CEE_SUB_OVF_UN:
1018                 ins->type = bin_num_table [src1->type] [src2->type];
1019                 ins->opcode += ovfops_op_map [src1->type];
1020                 if (ins->type == STACK_R8)
1021                         ins->type = STACK_INV;
1022                 break;
1023         case OP_LOAD_MEMBASE:
1024                 ins->type = STACK_PTR;
1025                 break;
1026         case OP_LOADI1_MEMBASE:
1027         case OP_LOADU1_MEMBASE:
1028         case OP_LOADI2_MEMBASE:
1029         case OP_LOADU2_MEMBASE:
1030         case OP_LOADI4_MEMBASE:
1031         case OP_LOADU4_MEMBASE:
1032                 ins->type = STACK_PTR;
1033                 break;
1034         case OP_LOADI8_MEMBASE:
1035                 ins->type = STACK_I8;
1036                 break;
1037         case OP_LOADR4_MEMBASE:
1038         case OP_LOADR8_MEMBASE:
1039                 ins->type = STACK_R8;
1040                 break;
1041         default:
1042                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
1043                 break;
1044         }
1045
1046         if (ins->type == STACK_MP)
1047                 ins->klass = mono_defaults.object_class;
1048 }
1049
1050 static const char 
1051 ldind_type [] = {
1052         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
1053 };
1054
1055 #if 0
1056
1057 static const char
1058 param_table [STACK_MAX] [STACK_MAX] = {
1059         {0},
1060 };
1061
1062 static int
1063 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
1064         int i;
1065
1066         if (sig->hasthis) {
1067                 switch (args->type) {
1068                 case STACK_I4:
1069                 case STACK_I8:
1070                 case STACK_R8:
1071                 case STACK_VTYPE:
1072                 case STACK_INV:
1073                         return 0;
1074                 }
1075                 args++;
1076         }
1077         for (i = 0; i < sig->param_count; ++i) {
1078                 switch (args [i].type) {
1079                 case STACK_INV:
1080                         return 0;
1081                 case STACK_MP:
1082                         if (!sig->params [i]->byref)
1083                                 return 0;
1084                         continue;
1085                 case STACK_OBJ:
1086                         if (sig->params [i]->byref)
1087                                 return 0;
1088                         switch (sig->params [i]->type) {
1089                         case MONO_TYPE_CLASS:
1090                         case MONO_TYPE_STRING:
1091                         case MONO_TYPE_OBJECT:
1092                         case MONO_TYPE_SZARRAY:
1093                         case MONO_TYPE_ARRAY:
1094                                 break;
1095                         default:
1096                                 return 0;
1097                         }
1098                         continue;
1099                 case STACK_R8:
1100                         if (sig->params [i]->byref)
1101                                 return 0;
1102                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1103                                 return 0;
1104                         continue;
1105                 case STACK_PTR:
1106                 case STACK_I4:
1107                 case STACK_I8:
1108                 case STACK_VTYPE:
1109                         break;
1110                 }
1111                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1112                         return 0;*/
1113         }
1114         return 1;
1115 }
1116 #endif
1117
1118 /*
1119  * When we need a pointer to the current domain many times in a method, we
1120  * call mono_domain_get() once and we store the result in a local variable.
1121  * This function returns the variable that represents the MonoDomain*.
1122  */
1123 inline static MonoInst *
1124 mono_get_domainvar (MonoCompile *cfg)
1125 {
1126         if (!cfg->domainvar)
1127                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1128         return cfg->domainvar;
1129 }
1130
1131 /*
1132  * The got_var contains the address of the Global Offset Table when AOT 
1133  * compiling.
1134  */
1135 MonoInst *
1136 mono_get_got_var (MonoCompile *cfg)
1137 {
1138 #ifdef MONO_ARCH_NEED_GOT_VAR
1139         if (!cfg->compile_aot)
1140                 return NULL;
1141         if (!cfg->got_var) {
1142                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1143         }
1144         return cfg->got_var;
1145 #else
1146         return NULL;
1147 #endif
1148 }
1149
1150 static MonoInst *
1151 mono_get_vtable_var (MonoCompile *cfg)
1152 {
1153         g_assert (cfg->generic_sharing_context);
1154
1155         if (!cfg->rgctx_var) {
1156                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1157                 /* force the var to be stack allocated */
1158                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
1159         }
1160
1161         return cfg->rgctx_var;
1162 }
1163
1164 static MonoType*
1165 type_from_stack_type (MonoInst *ins) {
1166         switch (ins->type) {
1167         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1168         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1169         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1170         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1171         case STACK_MP:
1172                 return &ins->klass->this_arg;
1173         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1174         case STACK_VTYPE: return &ins->klass->byval_arg;
1175         default:
1176                 g_error ("stack type %d to monotype not handled\n", ins->type);
1177         }
1178         return NULL;
1179 }
1180
1181 static G_GNUC_UNUSED int
1182 type_to_stack_type (MonoType *t)
1183 {
1184         t = mono_type_get_underlying_type (t);
1185         switch (t->type) {
1186         case MONO_TYPE_I1:
1187         case MONO_TYPE_U1:
1188         case MONO_TYPE_BOOLEAN:
1189         case MONO_TYPE_I2:
1190         case MONO_TYPE_U2:
1191         case MONO_TYPE_CHAR:
1192         case MONO_TYPE_I4:
1193         case MONO_TYPE_U4:
1194                 return STACK_I4;
1195         case MONO_TYPE_I:
1196         case MONO_TYPE_U:
1197         case MONO_TYPE_PTR:
1198         case MONO_TYPE_FNPTR:
1199                 return STACK_PTR;
1200         case MONO_TYPE_CLASS:
1201         case MONO_TYPE_STRING:
1202         case MONO_TYPE_OBJECT:
1203         case MONO_TYPE_SZARRAY:
1204         case MONO_TYPE_ARRAY:    
1205                 return STACK_OBJ;
1206         case MONO_TYPE_I8:
1207         case MONO_TYPE_U8:
1208                 return STACK_I8;
1209         case MONO_TYPE_R4:
1210         case MONO_TYPE_R8:
1211                 return STACK_R8;
1212         case MONO_TYPE_VALUETYPE:
1213         case MONO_TYPE_TYPEDBYREF:
1214                 return STACK_VTYPE;
1215         case MONO_TYPE_GENERICINST:
1216                 if (mono_type_generic_inst_is_valuetype (t))
1217                         return STACK_VTYPE;
1218                 else
1219                         return STACK_OBJ;
1220                 break;
1221         default:
1222                 g_assert_not_reached ();
1223         }
1224
1225         return -1;
1226 }
1227
1228 static MonoClass*
1229 array_access_to_klass (int opcode)
1230 {
1231         switch (opcode) {
1232         case CEE_LDELEM_U1:
1233                 return mono_defaults.byte_class;
1234         case CEE_LDELEM_U2:
1235                 return mono_defaults.uint16_class;
1236         case CEE_LDELEM_I:
1237         case CEE_STELEM_I:
1238                 return mono_defaults.int_class;
1239         case CEE_LDELEM_I1:
1240         case CEE_STELEM_I1:
1241                 return mono_defaults.sbyte_class;
1242         case CEE_LDELEM_I2:
1243         case CEE_STELEM_I2:
1244                 return mono_defaults.int16_class;
1245         case CEE_LDELEM_I4:
1246         case CEE_STELEM_I4:
1247                 return mono_defaults.int32_class;
1248         case CEE_LDELEM_U4:
1249                 return mono_defaults.uint32_class;
1250         case CEE_LDELEM_I8:
1251         case CEE_STELEM_I8:
1252                 return mono_defaults.int64_class;
1253         case CEE_LDELEM_R4:
1254         case CEE_STELEM_R4:
1255                 return mono_defaults.single_class;
1256         case CEE_LDELEM_R8:
1257         case CEE_STELEM_R8:
1258                 return mono_defaults.double_class;
1259         case CEE_LDELEM_REF:
1260         case CEE_STELEM_REF:
1261                 return mono_defaults.object_class;
1262         default:
1263                 g_assert_not_reached ();
1264         }
1265         return NULL;
1266 }
1267
1268 /*
1269  * We try to share variables when possible
1270  */
1271 static MonoInst *
1272 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1273 {
1274         MonoInst *res;
1275         int pos, vnum;
1276
1277         /* inlining can result in deeper stacks */ 
1278         if (slot >= cfg->header->max_stack)
1279                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1280
1281         pos = ins->type - 1 + slot * STACK_MAX;
1282
1283         switch (ins->type) {
1284         case STACK_I4:
1285         case STACK_I8:
1286         case STACK_R8:
1287         case STACK_PTR:
1288         case STACK_MP:
1289         case STACK_OBJ:
1290                 if ((vnum = cfg->intvars [pos]))
1291                         return cfg->varinfo [vnum];
1292                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1293                 cfg->intvars [pos] = res->inst_c0;
1294                 break;
1295         default:
1296                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1297         }
1298         return res;
1299 }
1300
1301 static void
1302 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1303 {
1304         /* 
1305          * Don't use this if a generic_context is set, since that means AOT can't
1306          * look up the method using just the image+token.
1307          * table == 0 means this is a reference made from a wrapper.
1308          */
1309         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1310                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1311                 jump_info_token->image = image;
1312                 jump_info_token->token = token;
1313                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1314         }
1315 }
1316
1317 /*
1318  * This function is called to handle items that are left on the evaluation stack
1319  * at basic block boundaries. What happens is that we save the values to local variables
1320  * and we reload them later when first entering the target basic block (with the
1321  * handle_loaded_temps () function).
1322  * A single joint point will use the same variables (stored in the array bb->out_stack or
1323  * bb->in_stack, if the basic block is before or after the joint point).
1324  *
1325  * This function needs to be called _before_ emitting the last instruction of
1326  * the bb (i.e. before emitting a branch).
1327  * If the stack merge fails at a join point, cfg->unverifiable is set.
1328  */
1329 static void
1330 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1331 {
1332         int i, bindex;
1333         MonoBasicBlock *bb = cfg->cbb;
1334         MonoBasicBlock *outb;
1335         MonoInst *inst, **locals;
1336         gboolean found;
1337
1338         if (!count)
1339                 return;
1340         if (cfg->verbose_level > 3)
1341                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1342         if (!bb->out_scount) {
1343                 bb->out_scount = count;
1344                 //printf ("bblock %d has out:", bb->block_num);
1345                 found = FALSE;
1346                 for (i = 0; i < bb->out_count; ++i) {
1347                         outb = bb->out_bb [i];
1348                         /* exception handlers are linked, but they should not be considered for stack args */
1349                         if (outb->flags & BB_EXCEPTION_HANDLER)
1350                                 continue;
1351                         //printf (" %d", outb->block_num);
1352                         if (outb->in_stack) {
1353                                 found = TRUE;
1354                                 bb->out_stack = outb->in_stack;
1355                                 break;
1356                         }
1357                 }
1358                 //printf ("\n");
1359                 if (!found) {
1360                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1361                         for (i = 0; i < count; ++i) {
1362                                 /* 
1363                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1364                                  * stack slot and if they are of the same type.
1365                                  * This won't cause conflicts since if 'local' is used to 
1366                                  * store one of the values in the in_stack of a bblock, then
1367                                  * the same variable will be used for the same outgoing stack 
1368                                  * slot as well. 
1369                                  * This doesn't work when inlining methods, since the bblocks
1370                                  * in the inlined methods do not inherit their in_stack from
1371                                  * the bblock they are inlined to. See bug #58863 for an
1372                                  * example.
1373                                  */
1374                                 if (cfg->inlined_method)
1375                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1376                                 else
1377                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1378                         }
1379                 }
1380         }
1381
1382         for (i = 0; i < bb->out_count; ++i) {
1383                 outb = bb->out_bb [i];
1384                 /* exception handlers are linked, but they should not be considered for stack args */
1385                 if (outb->flags & BB_EXCEPTION_HANDLER)
1386                         continue;
1387                 if (outb->in_scount) {
1388                         if (outb->in_scount != bb->out_scount) {
1389                                 cfg->unverifiable = TRUE;
1390                                 return;
1391                         }
1392                         continue; /* check they are the same locals */
1393                 }
1394                 outb->in_scount = count;
1395                 outb->in_stack = bb->out_stack;
1396         }
1397
1398         locals = bb->out_stack;
1399         cfg->cbb = bb;
1400         for (i = 0; i < count; ++i) {
1401                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1402                 inst->cil_code = sp [i]->cil_code;
1403                 sp [i] = locals [i];
1404                 if (cfg->verbose_level > 3)
1405                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1406         }
1407
1408         /*
1409          * It is possible that the out bblocks already have in_stack assigned, and
1410          * the in_stacks differ. In this case, we will store to all the different 
1411          * in_stacks.
1412          */
1413
1414         found = TRUE;
1415         bindex = 0;
1416         while (found) {
1417                 /* Find a bblock which has a different in_stack */
1418                 found = FALSE;
1419                 while (bindex < bb->out_count) {
1420                         outb = bb->out_bb [bindex];
1421                         /* exception handlers are linked, but they should not be considered for stack args */
1422                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1423                                 bindex++;
1424                                 continue;
1425                         }
1426                         if (outb->in_stack != locals) {
1427                                 for (i = 0; i < count; ++i) {
1428                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1429                                         inst->cil_code = sp [i]->cil_code;
1430                                         sp [i] = locals [i];
1431                                         if (cfg->verbose_level > 3)
1432                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1433                                 }
1434                                 locals = outb->in_stack;
1435                                 found = TRUE;
1436                                 break;
1437                         }
1438                         bindex ++;
1439                 }
1440         }
1441 }
1442
1443 /* Emit code which loads interface_offsets [klass->interface_id]
1444  * The array is stored in memory before vtable.
1445 */
1446 static void
1447 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1448 {
1449         if (cfg->compile_aot) {
1450                 int ioffset_reg = alloc_preg (cfg);
1451                 int iid_reg = alloc_preg (cfg);
1452
1453                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1454                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1455                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1456         }
1457         else {
1458                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1459         }
1460 }
1461
1462 static void
1463 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1464 {
1465         int ibitmap_reg = alloc_preg (cfg);
1466 #ifdef COMPRESSED_INTERFACE_BITMAP
1467         MonoInst *args [2];
1468         MonoInst *res, *ins;
1469         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1470         MONO_ADD_INS (cfg->cbb, ins);
1471         args [0] = ins;
1472         if (cfg->compile_aot)
1473                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1474         else
1475                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1476         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1477         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1478 #else
1479         int ibitmap_byte_reg = alloc_preg (cfg);
1480
1481         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1482
1483         if (cfg->compile_aot) {
1484                 int iid_reg = alloc_preg (cfg);
1485                 int shifted_iid_reg = alloc_preg (cfg);
1486                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1487                 int masked_iid_reg = alloc_preg (cfg);
1488                 int iid_one_bit_reg = alloc_preg (cfg);
1489                 int iid_bit_reg = alloc_preg (cfg);
1490                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1491                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1492                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1493                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1494                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1495                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1496                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1497                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1498         } else {
1499                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1500                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1501         }
1502 #endif
1503 }
1504
1505 /* 
1506  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1507  * stored in "klass_reg" implements the interface "klass".
1508  */
1509 static void
1510 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1511 {
1512         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1513 }
1514
1515 /* 
1516  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1517  * stored in "vtable_reg" implements the interface "klass".
1518  */
1519 static void
1520 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1521 {
1522         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1523 }
1524
1525 /* 
1526  * Emit code which checks whenever the interface id of @klass is smaller than
1527  * than the value given by max_iid_reg.
1528 */
1529 static void
1530 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1531                                                  MonoBasicBlock *false_target)
1532 {
1533         if (cfg->compile_aot) {
1534                 int iid_reg = alloc_preg (cfg);
1535                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1536                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1537         }
1538         else
1539                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1540         if (false_target)
1541                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1542         else
1543                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1544 }
1545
1546 /* Same as above, but obtains max_iid from a vtable */
1547 static void
1548 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1549                                                                  MonoBasicBlock *false_target)
1550 {
1551         int max_iid_reg = alloc_preg (cfg);
1552                 
1553         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1554         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1555 }
1556
1557 /* Same as above, but obtains max_iid from a klass */
1558 static void
1559 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1560                                                                  MonoBasicBlock *false_target)
1561 {
1562         int max_iid_reg = alloc_preg (cfg);
1563
1564         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1565         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1566 }
1567
1568 static void
1569 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1570 {
1571         int idepth_reg = alloc_preg (cfg);
1572         int stypes_reg = alloc_preg (cfg);
1573         int stype = alloc_preg (cfg);
1574
1575         mono_class_setup_supertypes (klass);
1576
1577         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1578                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1579                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1580                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1581         }
1582         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1583         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1584         if (klass_ins) {
1585                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1586         } else if (cfg->compile_aot) {
1587                 int const_reg = alloc_preg (cfg);
1588                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1589                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1590         } else {
1591                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1592         }
1593         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1594 }
1595
1596 static void
1597 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1598 {
1599         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1600 }
1601
1602 static void
1603 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1604 {
1605         int intf_reg = alloc_preg (cfg);
1606
1607         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1608         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1609         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1610         if (true_target)
1611                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1612         else
1613                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1614 }
1615
1616 /*
1617  * Variant of the above that takes a register to the class, not the vtable.
1618  */
1619 static void
1620 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1621 {
1622         int intf_bit_reg = alloc_preg (cfg);
1623
1624         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1625         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1626         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1627         if (true_target)
1628                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1629         else
1630                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1631 }
1632
1633 static inline void
1634 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1635 {
1636         if (klass_inst) {
1637                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1638         } else if (cfg->compile_aot) {
1639                 int const_reg = alloc_preg (cfg);
1640                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1641                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1642         } else {
1643                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1644         }
1645         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1646 }
1647
1648 static inline void
1649 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1650 {
1651         mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1652 }
1653
1654 static inline void
1655 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1656 {
1657         if (cfg->compile_aot) {
1658                 int const_reg = alloc_preg (cfg);
1659                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1660                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1661         } else {
1662                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1663         }
1664         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1665 }
1666
1667 static void
1668 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1669         
1670 static void
1671 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1672 {
1673         if (klass->rank) {
1674                 int rank_reg = alloc_preg (cfg);
1675                 int eclass_reg = alloc_preg (cfg);
1676
1677                 g_assert (!klass_inst);
1678                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1679                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1680                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1681                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1682                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1683                 if (klass->cast_class == mono_defaults.object_class) {
1684                         int parent_reg = alloc_preg (cfg);
1685                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1686                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1687                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1688                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1689                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1690                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1691                 } else if (klass->cast_class == mono_defaults.enum_class) {
1692                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1693                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1694                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1695                 } else {
1696                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1697                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1698                 }
1699
1700                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1701                         /* Check that the object is a vector too */
1702                         int bounds_reg = alloc_preg (cfg);
1703                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1704                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1705                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1706                 }
1707         } else {
1708                 int idepth_reg = alloc_preg (cfg);
1709                 int stypes_reg = alloc_preg (cfg);
1710                 int stype = alloc_preg (cfg);
1711
1712                 mono_class_setup_supertypes (klass);
1713
1714                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1715                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1716                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1717                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1718                 }
1719                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1720                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1721                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1722         }
1723 }
1724
1725 static void
1726 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1727 {
1728         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1729 }
1730
1731 static void 
1732 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1733 {
1734         int val_reg;
1735
1736         g_assert (val == 0);
1737
1738         if (align == 0)
1739                 align = 4;
1740
1741         if ((size <= 4) && (size <= align)) {
1742                 switch (size) {
1743                 case 1:
1744                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1745                         return;
1746                 case 2:
1747                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1748                         return;
1749                 case 4:
1750                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1751                         return;
1752 #if SIZEOF_REGISTER == 8
1753                 case 8:
1754                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1755                         return;
1756 #endif
1757                 }
1758         }
1759
1760         val_reg = alloc_preg (cfg);
1761
1762         if (SIZEOF_REGISTER == 8)
1763                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1764         else
1765                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1766
1767         if (align < 4) {
1768                 /* This could be optimized further if neccesary */
1769                 while (size >= 1) {
1770                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1771                         offset += 1;
1772                         size -= 1;
1773                 }
1774                 return;
1775         }       
1776
1777 #if !NO_UNALIGNED_ACCESS
1778         if (SIZEOF_REGISTER == 8) {
1779                 if (offset % 8) {
1780                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1781                         offset += 4;
1782                         size -= 4;
1783                 }
1784                 while (size >= 8) {
1785                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1786                         offset += 8;
1787                         size -= 8;
1788                 }
1789         }       
1790 #endif
1791
1792         while (size >= 4) {
1793                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1794                 offset += 4;
1795                 size -= 4;
1796         }
1797         while (size >= 2) {
1798                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1799                 offset += 2;
1800                 size -= 2;
1801         }
1802         while (size >= 1) {
1803                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1804                 offset += 1;
1805                 size -= 1;
1806         }
1807 }
1808
1809 void 
1810 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1811 {
1812         int cur_reg;
1813
1814         if (align == 0)
1815                 align = 4;
1816
1817         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1818         g_assert (size < 10000);
1819
1820         if (align < 4) {
1821                 /* This could be optimized further if neccesary */
1822                 while (size >= 1) {
1823                         cur_reg = alloc_preg (cfg);
1824                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1825                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1826                         doffset += 1;
1827                         soffset += 1;
1828                         size -= 1;
1829                 }
1830         }
1831
1832 #if !NO_UNALIGNED_ACCESS
1833         if (SIZEOF_REGISTER == 8) {
1834                 while (size >= 8) {
1835                         cur_reg = alloc_preg (cfg);
1836                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1837                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1838                         doffset += 8;
1839                         soffset += 8;
1840                         size -= 8;
1841                 }
1842         }       
1843 #endif
1844
1845         while (size >= 4) {
1846                 cur_reg = alloc_preg (cfg);
1847                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1848                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1849                 doffset += 4;
1850                 soffset += 4;
1851                 size -= 4;
1852         }
1853         while (size >= 2) {
1854                 cur_reg = alloc_preg (cfg);
1855                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1856                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1857                 doffset += 2;
1858                 soffset += 2;
1859                 size -= 2;
1860         }
1861         while (size >= 1) {
1862                 cur_reg = alloc_preg (cfg);
1863                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1864                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1865                 doffset += 1;
1866                 soffset += 1;
1867                 size -= 1;
1868         }
1869 }
1870
1871 static int
1872 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
1873 {
1874         if (type->byref)
1875                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1876
1877 handle_enum:
1878         type = mini_get_basic_type_from_generic (gsctx, type);
1879         switch (type->type) {
1880         case MONO_TYPE_VOID:
1881                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1882         case MONO_TYPE_I1:
1883         case MONO_TYPE_U1:
1884         case MONO_TYPE_BOOLEAN:
1885         case MONO_TYPE_I2:
1886         case MONO_TYPE_U2:
1887         case MONO_TYPE_CHAR:
1888         case MONO_TYPE_I4:
1889         case MONO_TYPE_U4:
1890                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1891         case MONO_TYPE_I:
1892         case MONO_TYPE_U:
1893         case MONO_TYPE_PTR:
1894         case MONO_TYPE_FNPTR:
1895                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1896         case MONO_TYPE_CLASS:
1897         case MONO_TYPE_STRING:
1898         case MONO_TYPE_OBJECT:
1899         case MONO_TYPE_SZARRAY:
1900         case MONO_TYPE_ARRAY:    
1901                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1902         case MONO_TYPE_I8:
1903         case MONO_TYPE_U8:
1904                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1905         case MONO_TYPE_R4:
1906         case MONO_TYPE_R8:
1907                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1908         case MONO_TYPE_VALUETYPE:
1909                 if (type->data.klass->enumtype) {
1910                         type = mono_class_enum_basetype (type->data.klass);
1911                         goto handle_enum;
1912                 } else
1913                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1914         case MONO_TYPE_TYPEDBYREF:
1915                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1916         case MONO_TYPE_GENERICINST:
1917                 type = &type->data.generic_class->container_class->byval_arg;
1918                 goto handle_enum;
1919         case MONO_TYPE_VAR:
1920         case MONO_TYPE_MVAR:
1921                 /* gsharedvt */
1922                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1923         default:
1924                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1925         }
1926         return -1;
1927 }
1928
1929 /*
1930  * target_type_is_incompatible:
1931  * @cfg: MonoCompile context
1932  *
1933  * Check that the item @arg on the evaluation stack can be stored
1934  * in the target type (can be a local, or field, etc).
1935  * The cfg arg can be used to check if we need verification or just
1936  * validity checks.
1937  *
1938  * Returns: non-0 value if arg can't be stored on a target.
1939  */
1940 static int
1941 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
1942 {
1943         MonoType *simple_type;
1944         MonoClass *klass;
1945
1946         if (target->byref) {
1947                 /* FIXME: check that the pointed to types match */
1948                 if (arg->type == STACK_MP)
1949                         return arg->klass != mono_class_from_mono_type (target);
1950                 if (arg->type == STACK_PTR)
1951                         return 0;
1952                 return 1;
1953         }
1954
1955         simple_type = mono_type_get_underlying_type (target);
1956         switch (simple_type->type) {
1957         case MONO_TYPE_VOID:
1958                 return 1;
1959         case MONO_TYPE_I1:
1960         case MONO_TYPE_U1:
1961         case MONO_TYPE_BOOLEAN:
1962         case MONO_TYPE_I2:
1963         case MONO_TYPE_U2:
1964         case MONO_TYPE_CHAR:
1965         case MONO_TYPE_I4:
1966         case MONO_TYPE_U4:
1967                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1968                         return 1;
1969                 return 0;
1970         case MONO_TYPE_PTR:
1971                 /* STACK_MP is needed when setting pinned locals */
1972                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
1973                         return 1;
1974                 return 0;
1975         case MONO_TYPE_I:
1976         case MONO_TYPE_U:
1977         case MONO_TYPE_FNPTR:
1978                 /* 
1979                  * Some opcodes like ldloca returns 'transient pointers' which can be stored in
1980                  * in native int. (#688008).
1981                  */
1982                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
1983                         return 1;
1984                 return 0;
1985         case MONO_TYPE_CLASS:
1986         case MONO_TYPE_STRING:
1987         case MONO_TYPE_OBJECT:
1988         case MONO_TYPE_SZARRAY:
1989         case MONO_TYPE_ARRAY:    
1990                 if (arg->type != STACK_OBJ)
1991                         return 1;
1992                 /* FIXME: check type compatibility */
1993                 return 0;
1994         case MONO_TYPE_I8:
1995         case MONO_TYPE_U8:
1996                 if (arg->type != STACK_I8)
1997                         return 1;
1998                 return 0;
1999         case MONO_TYPE_R4:
2000         case MONO_TYPE_R8:
2001                 if (arg->type != STACK_R8)
2002                         return 1;
2003                 return 0;
2004         case MONO_TYPE_VALUETYPE:
2005                 if (arg->type != STACK_VTYPE)
2006                         return 1;
2007                 klass = mono_class_from_mono_type (simple_type);
2008                 if (klass != arg->klass)
2009                         return 1;
2010                 return 0;
2011         case MONO_TYPE_TYPEDBYREF:
2012                 if (arg->type != STACK_VTYPE)
2013                         return 1;
2014                 klass = mono_class_from_mono_type (simple_type);
2015                 if (klass != arg->klass)
2016                         return 1;
2017                 return 0;
2018         case MONO_TYPE_GENERICINST:
2019                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
2020                         if (arg->type != STACK_VTYPE)
2021                                 return 1;
2022                         klass = mono_class_from_mono_type (simple_type);
2023                         if (klass != arg->klass)
2024                                 return 1;
2025                         return 0;
2026                 } else {
2027                         if (arg->type != STACK_OBJ)
2028                                 return 1;
2029                         /* FIXME: check type compatibility */
2030                         return 0;
2031                 }
2032         case MONO_TYPE_VAR:
2033         case MONO_TYPE_MVAR:
2034                 g_assert (cfg->generic_sharing_context);
2035                 if (mini_type_var_is_vt (cfg, simple_type)) {
2036                         if (arg->type != STACK_VTYPE)
2037                                 return 1;
2038                 } else {
2039                         if (arg->type != STACK_OBJ)
2040                                 return 1;
2041                 }
2042                 return 0;
2043         default:
2044                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
2045         }
2046         return 1;
2047 }
2048
2049 /*
2050  * Prepare arguments for passing to a function call.
2051  * Return a non-zero value if the arguments can't be passed to the given
2052  * signature.
2053  * The type checks are not yet complete and some conversions may need
2054  * casts on 32 or 64 bit architectures.
2055  *
2056  * FIXME: implement this using target_type_is_incompatible ()
2057  */
2058 static int
2059 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
2060 {
2061         MonoType *simple_type;
2062         int i;
2063
2064         if (sig->hasthis) {
2065                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
2066                         return 1;
2067                 args++;
2068         }
2069         for (i = 0; i < sig->param_count; ++i) {
2070                 if (sig->params [i]->byref) {
2071                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
2072                                 return 1;
2073                         continue;
2074                 }
2075                 simple_type = sig->params [i];
2076                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
2077 handle_enum:
2078                 switch (simple_type->type) {
2079                 case MONO_TYPE_VOID:
2080                         return 1;
2081                         continue;
2082                 case MONO_TYPE_I1:
2083                 case MONO_TYPE_U1:
2084                 case MONO_TYPE_BOOLEAN:
2085                 case MONO_TYPE_I2:
2086                 case MONO_TYPE_U2:
2087                 case MONO_TYPE_CHAR:
2088                 case MONO_TYPE_I4:
2089                 case MONO_TYPE_U4:
2090                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
2091                                 return 1;
2092                         continue;
2093                 case MONO_TYPE_I:
2094                 case MONO_TYPE_U:
2095                 case MONO_TYPE_PTR:
2096                 case MONO_TYPE_FNPTR:
2097                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2098                                 return 1;
2099                         continue;
2100                 case MONO_TYPE_CLASS:
2101                 case MONO_TYPE_STRING:
2102                 case MONO_TYPE_OBJECT:
2103                 case MONO_TYPE_SZARRAY:
2104                 case MONO_TYPE_ARRAY:    
2105                         if (args [i]->type != STACK_OBJ)
2106                                 return 1;
2107                         continue;
2108                 case MONO_TYPE_I8:
2109                 case MONO_TYPE_U8:
2110                         if (args [i]->type != STACK_I8)
2111                                 return 1;
2112                         continue;
2113                 case MONO_TYPE_R4:
2114                 case MONO_TYPE_R8:
2115                         if (args [i]->type != STACK_R8)
2116                                 return 1;
2117                         continue;
2118                 case MONO_TYPE_VALUETYPE:
2119                         if (simple_type->data.klass->enumtype) {
2120                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2121                                 goto handle_enum;
2122                         }
2123                         if (args [i]->type != STACK_VTYPE)
2124                                 return 1;
2125                         continue;
2126                 case MONO_TYPE_TYPEDBYREF:
2127                         if (args [i]->type != STACK_VTYPE)
2128                                 return 1;
2129                         continue;
2130                 case MONO_TYPE_GENERICINST:
2131                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2132                         goto handle_enum;
2133                 case MONO_TYPE_VAR:
2134                 case MONO_TYPE_MVAR:
2135                         /* gsharedvt */
2136                         if (args [i]->type != STACK_VTYPE)
2137                                 return 1;
2138                         continue;
2139                 default:
2140                         g_error ("unknown type 0x%02x in check_call_signature",
2141                                  simple_type->type);
2142                 }
2143         }
2144         return 0;
2145 }
2146
2147 static int
2148 callvirt_to_call (int opcode)
2149 {
2150         switch (opcode) {
2151         case OP_CALLVIRT:
2152                 return OP_CALL;
2153         case OP_VOIDCALLVIRT:
2154                 return OP_VOIDCALL;
2155         case OP_FCALLVIRT:
2156                 return OP_FCALL;
2157         case OP_VCALLVIRT:
2158                 return OP_VCALL;
2159         case OP_LCALLVIRT:
2160                 return OP_LCALL;
2161         default:
2162                 g_assert_not_reached ();
2163         }
2164
2165         return -1;
2166 }
2167
2168 static int
2169 callvirt_to_call_membase (int opcode)
2170 {
2171         switch (opcode) {
2172         case OP_CALLVIRT:
2173                 return OP_CALL_MEMBASE;
2174         case OP_VOIDCALLVIRT:
2175                 return OP_VOIDCALL_MEMBASE;
2176         case OP_FCALLVIRT:
2177                 return OP_FCALL_MEMBASE;
2178         case OP_LCALLVIRT:
2179                 return OP_LCALL_MEMBASE;
2180         case OP_VCALLVIRT:
2181                 return OP_VCALL_MEMBASE;
2182         default:
2183                 g_assert_not_reached ();
2184         }
2185
2186         return -1;
2187 }
2188
2189 #ifdef MONO_ARCH_HAVE_IMT
2190 /* Either METHOD or IMT_ARG needs to be set */
2191 static void
2192 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoMethod *method, MonoInst *imt_arg)
2193 {
2194         int method_reg;
2195
2196         if (COMPILE_LLVM (cfg)) {
2197                 method_reg = alloc_preg (cfg);
2198
2199                 if (imt_arg) {
2200                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2201                 } else if (cfg->compile_aot) {
2202                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2203                 } else {
2204                         MonoInst *ins;
2205                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2206                         ins->inst_p0 = method;
2207                         ins->dreg = method_reg;
2208                         MONO_ADD_INS (cfg->cbb, ins);
2209                 }
2210
2211 #ifdef ENABLE_LLVM
2212                 call->imt_arg_reg = method_reg;
2213 #endif
2214 #ifdef MONO_ARCH_IMT_REG
2215         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2216 #else
2217         /* Need this to keep the IMT arg alive */
2218         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2219 #endif
2220                 return;
2221         }
2222
2223 #ifdef MONO_ARCH_IMT_REG
2224         method_reg = alloc_preg (cfg);
2225
2226         if (imt_arg) {
2227                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2228         } else if (cfg->compile_aot) {
2229                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, method, MONO_PATCH_INFO_METHODCONST);
2230         } else {
2231                 MonoInst *ins;
2232                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2233                 ins->inst_p0 = method;
2234                 ins->dreg = method_reg;
2235                 MONO_ADD_INS (cfg->cbb, ins);
2236         }
2237
2238         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2239 #else
2240         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2241 #endif
2242 }
2243 #endif
2244
2245 static MonoJumpInfo *
2246 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2247 {
2248         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2249
2250         ji->ip.i = ip;
2251         ji->type = type;
2252         ji->data.target = target;
2253
2254         return ji;
2255 }
2256
2257 static int
2258 mini_class_check_context_used (MonoCompile *cfg, MonoClass *klass)
2259 {
2260         if (cfg->generic_sharing_context)
2261                 return mono_class_check_context_used (klass);
2262         else
2263                 return 0;
2264 }
2265
2266 static int
2267 mini_method_check_context_used (MonoCompile *cfg, MonoMethod *method)
2268 {
2269         if (cfg->generic_sharing_context)
2270                 return mono_method_check_context_used (method);
2271         else
2272                 return 0;
2273 }
2274
2275 /*
2276  * check_method_sharing:
2277  *
2278  *   Check whenever the vtable or an mrgctx needs to be passed when calling CMETHOD.
2279  */
2280 static void
2281 check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_vtable, gboolean *out_pass_mrgctx)
2282 {
2283         gboolean pass_vtable = FALSE;
2284         gboolean pass_mrgctx = FALSE;
2285
2286         if (((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
2287                 (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
2288                 gboolean sharable = FALSE;
2289
2290                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2291                         sharable = TRUE;
2292                 } else {
2293                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2294                         MonoGenericContext *context = mini_class_get_context (cmethod->klass);
2295                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2296
2297                         sharable = sharing_enabled && context_sharable;
2298                 }
2299
2300                 /*
2301                  * Pass vtable iff target method might
2302                  * be shared, which means that sharing
2303                  * is enabled for its class and its
2304                  * context is sharable (and it's not a
2305                  * generic method).
2306                  */
2307                 if (sharable && !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
2308                         pass_vtable = TRUE;
2309         }
2310
2311         if (mini_method_get_context (cmethod) &&
2312                 mini_method_get_context (cmethod)->method_inst) {
2313                 g_assert (!pass_vtable);
2314
2315                 if (mono_method_is_generic_sharable (cmethod, TRUE)) {
2316                         pass_mrgctx = TRUE;
2317                 } else {
2318                         gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
2319                         MonoGenericContext *context = mini_method_get_context (cmethod);
2320                         gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
2321
2322                         if (sharing_enabled && context_sharable)
2323                                 pass_mrgctx = TRUE;
2324                         if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, mono_method_signature (cmethod)))
2325                                 pass_mrgctx = TRUE;
2326                 }
2327         }
2328
2329         if (out_pass_vtable)
2330                 *out_pass_vtable = pass_vtable;
2331         if (out_pass_mrgctx)
2332                 *out_pass_mrgctx = pass_mrgctx;
2333 }
2334
2335 inline static MonoCallInst *
2336 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2337                                          MonoInst **args, int calli, int virtual, int tail, int rgctx, int unbox_trampoline)
2338 {
2339         MonoCallInst *call;
2340 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2341         int i;
2342 #endif
2343
2344         if (tail)
2345                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2346         else
2347                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2348
2349         call->args = args;
2350         call->signature = sig;
2351         call->rgctx_reg = rgctx;
2352
2353         type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
2354
2355         if (tail) {
2356                 if (mini_type_is_vtype (cfg, sig->ret)) {
2357                         call->vret_var = cfg->vret_addr;
2358                         //g_assert_not_reached ();
2359                 }
2360         } else if (mini_type_is_vtype (cfg, sig->ret)) {
2361                 MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
2362                 MonoInst *loada;
2363
2364                 temp->backend.is_pinvoke = sig->pinvoke;
2365
2366                 /*
2367                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2368                  * address of return value to increase optimization opportunities.
2369                  * Before vtype decomposition, the dreg of the call ins itself represents the
2370                  * fact the call modifies the return value. After decomposition, the call will
2371                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2372                  * will be transformed into an LDADDR.
2373                  */
2374                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2375                 loada->dreg = alloc_preg (cfg);
2376                 loada->inst_p0 = temp;
2377                 /* We reference the call too since call->dreg could change during optimization */
2378                 loada->inst_p1 = call;
2379                 MONO_ADD_INS (cfg->cbb, loada);
2380
2381                 call->inst.dreg = temp->dreg;
2382
2383                 call->vret_var = loada;
2384         } else if (!MONO_TYPE_IS_VOID (sig->ret))
2385                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2386
2387 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
2388         if (COMPILE_SOFT_FLOAT (cfg)) {
2389                 /* 
2390                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2391                  * an icall, but that cannot be done during the call sequence since it would clobber
2392                  * the call registers + the stack. So we do it before emitting the call.
2393                  */
2394                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2395                         MonoType *t;
2396                         MonoInst *in = call->args [i];
2397
2398                         if (i >= sig->hasthis)
2399                                 t = sig->params [i - sig->hasthis];
2400                         else
2401                                 t = &mono_defaults.int_class->byval_arg;
2402                         t = mono_type_get_underlying_type (t);
2403
2404                         if (!t->byref && t->type == MONO_TYPE_R4) {
2405                                 MonoInst *iargs [1];
2406                                 MonoInst *conv;
2407
2408                                 iargs [0] = in;
2409                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2410
2411                                 /* The result will be in an int vreg */
2412                                 call->args [i] = conv;
2413                         }
2414                 }
2415         }
2416 #endif
2417
2418         call->need_unbox_trampoline = unbox_trampoline;
2419
2420 #ifdef ENABLE_LLVM
2421         if (COMPILE_LLVM (cfg))
2422                 mono_llvm_emit_call (cfg, call);
2423         else
2424                 mono_arch_emit_call (cfg, call);
2425 #else
2426         mono_arch_emit_call (cfg, call);
2427 #endif
2428
2429         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2430         cfg->flags |= MONO_CFG_HAS_CALLS;
2431         
2432         return call;
2433 }
2434
2435 static void
2436 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2437 {
2438 #ifdef MONO_ARCH_RGCTX_REG
2439         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2440         cfg->uses_rgctx_reg = TRUE;
2441         call->rgctx_reg = TRUE;
2442 #ifdef ENABLE_LLVM
2443         call->rgctx_arg_reg = rgctx_reg;
2444 #endif
2445 #else
2446         NOT_IMPLEMENTED;
2447 #endif
2448 }       
2449
2450 inline static MonoInst*
2451 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *imt_arg, MonoInst *rgctx_arg)
2452 {
2453         MonoCallInst *call;
2454         int rgctx_reg = -1;
2455
2456         if (rgctx_arg) {
2457                 rgctx_reg = mono_alloc_preg (cfg);
2458                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2459         }
2460
2461         call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
2462
2463         call->inst.sreg1 = addr->dreg;
2464
2465         if (imt_arg)
2466                 emit_imt_argument (cfg, call, NULL, imt_arg);
2467
2468         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2469
2470         if (rgctx_arg)
2471                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2472
2473         return (MonoInst*)call;
2474 }
2475
2476 static MonoInst*
2477 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2478
2479 static MonoInst*
2480 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type);
2481 static MonoInst*
2482 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, MonoRgctxInfoType rgctx_type);
2483
2484 static MonoInst*
2485 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig, gboolean tail,
2486                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *rgctx_arg)
2487 {
2488 #ifndef DISABLE_REMOTING
2489         gboolean might_be_remote = FALSE;
2490 #endif
2491         gboolean virtual = this != NULL;
2492         gboolean enable_for_aot = TRUE;
2493         int context_used;
2494         MonoCallInst *call;
2495         int rgctx_reg = 0;
2496         gboolean need_unbox_trampoline;
2497
2498         if (!sig)
2499                 sig = mono_method_signature (method);
2500
2501         if (rgctx_arg) {
2502                 rgctx_reg = mono_alloc_preg (cfg);
2503                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2504         }
2505
2506         if (method->string_ctor) {
2507                 /* Create the real signature */
2508                 /* FIXME: Cache these */
2509                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2510                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2511
2512                 sig = ctor_sig;
2513         }
2514
2515         context_used = mini_method_check_context_used (cfg, method);
2516
2517 #ifndef DISABLE_REMOTING
2518         might_be_remote = this && sig->hasthis &&
2519                 (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) &&
2520                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && (!MONO_CHECK_THIS (this) || context_used);
2521
2522         if (might_be_remote && context_used) {
2523                 MonoInst *addr;
2524
2525                 g_assert (cfg->generic_sharing_context);
2526
2527                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2528
2529                 return mono_emit_calli (cfg, sig, args, addr, NULL, NULL);
2530         }
2531 #endif
2532
2533         need_unbox_trampoline = method->klass == mono_defaults.object_class || (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE);
2534
2535         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
2536
2537 #ifndef DISABLE_REMOTING
2538         if (might_be_remote)
2539                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2540         else
2541 #endif
2542                 call->method = method;
2543         call->inst.flags |= MONO_INST_HAS_METHOD;
2544         call->inst.inst_left = this;
2545         call->tail_call = tail;
2546
2547         if (virtual) {
2548                 int vtable_reg, slot_reg, this_reg;
2549                 int offset;
2550
2551                 this_reg = this->dreg;
2552
2553                 if (ARCH_HAVE_DELEGATE_TRAMPOLINES && (method->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (method->name, "Invoke")) {
2554                         MonoInst *dummy_use;
2555
2556                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2557
2558                         /* Make a call to delegate->invoke_impl */
2559                         call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2560                         call->inst.inst_basereg = this_reg;
2561                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2562                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2563
2564                         /* We must emit a dummy use here because the delegate trampoline will
2565                         replace the 'this' argument with the delegate target making this activation
2566                         no longer a root for the delegate.
2567                         This is an issue for delegates that target collectible code such as dynamic
2568                         methods of GC'able assemblies.
2569
2570                         For a test case look into #667921.
2571
2572                         FIXME: a dummy use is not the best way to do it as the local register allocator
2573                         will put it on a caller save register and spil it around the call. 
2574                         Ideally, we would either put it on a callee save register or only do the store part.  
2575                          */
2576                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, args [0]);
2577
2578                         return (MonoInst*)call;
2579                 }
2580
2581                 if ((!cfg->compile_aot || enable_for_aot) && 
2582                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2583                          (MONO_METHOD_IS_FINAL (method) &&
2584                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2585                         !(mono_class_is_marshalbyref (method->klass) && context_used)) {
2586                         /* 
2587                          * the method is not virtual, we just need to ensure this is not null
2588                          * and then we can call the method directly.
2589                          */
2590 #ifndef DISABLE_REMOTING
2591                         if (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class) {
2592                                 /* 
2593                                  * The check above ensures method is not gshared, this is needed since
2594                                  * gshared methods can't have wrappers.
2595                                  */
2596                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2597                         }
2598 #endif
2599
2600                         if (!method->string_ctor)
2601                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2602
2603                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2604                 } else if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2605                         /*
2606                          * the method is virtual, but we can statically dispatch since either
2607                          * it's class or the method itself are sealed.
2608                          * But first we need to ensure it's not a null reference.
2609                          */
2610                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2611
2612                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2613                 } else {
2614                         call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2615
2616                         vtable_reg = alloc_preg (cfg);
2617                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2618                         if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2619                                 slot_reg = -1;
2620 #ifdef MONO_ARCH_HAVE_IMT
2621                                 if (mono_use_imt) {
2622                                         guint32 imt_slot = mono_method_get_imt_slot (method);
2623                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2624                                         slot_reg = vtable_reg;
2625                                         offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2626                                 }
2627 #endif
2628                                 if (slot_reg == -1) {
2629                                         slot_reg = alloc_preg (cfg);
2630                                         mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2631                                         offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2632                                 }
2633                         } else {
2634                                 slot_reg = vtable_reg;
2635                                 offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2636                                         ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2637 #ifdef MONO_ARCH_HAVE_IMT
2638                                 if (imt_arg) {
2639                                         g_assert (mono_method_signature (method)->generic_param_count);
2640                                         emit_imt_argument (cfg, call, call->method, imt_arg);
2641                                 }
2642 #endif
2643                         }
2644
2645                         call->inst.sreg1 = slot_reg;
2646                         call->inst.inst_offset = offset;
2647                         call->virtual = TRUE;
2648                 }
2649         }
2650
2651         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2652
2653         if (rgctx_arg)
2654                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2655
2656         return (MonoInst*)call;
2657 }
2658
2659 MonoInst*
2660 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2661 {
2662         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), FALSE, args, this, NULL, NULL);
2663 }
2664
2665 MonoInst*
2666 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2667                                            MonoInst **args)
2668 {
2669         MonoCallInst *call;
2670
2671         g_assert (sig);
2672
2673         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
2674         call->fptr = func;
2675
2676         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2677
2678         return (MonoInst*)call;
2679 }
2680
2681 MonoInst*
2682 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2683 {
2684         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2685
2686         g_assert (info);
2687
2688         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2689 }
2690
2691 /*
2692  * mono_emit_abs_call:
2693  *
2694  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2695  */
2696 inline static MonoInst*
2697 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2698                                         MonoMethodSignature *sig, MonoInst **args)
2699 {
2700         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2701         MonoInst *ins;
2702
2703         /* 
2704          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2705          * handle it.
2706          */
2707         if (cfg->abs_patches == NULL)
2708                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2709         g_hash_table_insert (cfg->abs_patches, ji, ji);
2710         ins = mono_emit_native_call (cfg, ji, sig, args);
2711         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2712         return ins;
2713 }
2714  
2715 static MonoInst*
2716 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2717 {
2718         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2719                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2720                         int widen_op = -1;
2721
2722                         /* 
2723                          * Native code might return non register sized integers 
2724                          * without initializing the upper bits.
2725                          */
2726                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2727                         case OP_LOADI1_MEMBASE:
2728                                 widen_op = OP_ICONV_TO_I1;
2729                                 break;
2730                         case OP_LOADU1_MEMBASE:
2731                                 widen_op = OP_ICONV_TO_U1;
2732                                 break;
2733                         case OP_LOADI2_MEMBASE:
2734                                 widen_op = OP_ICONV_TO_I2;
2735                                 break;
2736                         case OP_LOADU2_MEMBASE:
2737                                 widen_op = OP_ICONV_TO_U2;
2738                                 break;
2739                         default:
2740                                 break;
2741                         }
2742
2743                         if (widen_op != -1) {
2744                                 int dreg = alloc_preg (cfg);
2745                                 MonoInst *widen;
2746
2747                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2748                                 widen->type = ins->type;
2749                                 ins = widen;
2750                         }
2751                 }
2752         }
2753
2754         return ins;
2755 }
2756
2757 static MonoMethod*
2758 get_memcpy_method (void)
2759 {
2760         static MonoMethod *memcpy_method = NULL;
2761         if (!memcpy_method) {
2762                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2763                 if (!memcpy_method)
2764                         g_error ("Old corlib found. Install a new one");
2765         }
2766         return memcpy_method;
2767 }
2768
2769 static void
2770 create_write_barrier_bitmap (MonoCompile *cfg, MonoClass *klass, unsigned *wb_bitmap, int offset)
2771 {
2772         MonoClassField *field;
2773         gpointer iter = NULL;
2774
2775         while ((field = mono_class_get_fields (klass, &iter))) {
2776                 int foffset;
2777
2778                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2779                         continue;
2780                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2781                 if (mini_type_is_reference (cfg, mono_field_get_type (field))) {
2782                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2783                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2784                 } else {
2785                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2786                         if (field_class->has_references)
2787                                 create_write_barrier_bitmap (cfg, field_class, wb_bitmap, offset + foffset);
2788                 }
2789         }
2790 }
2791
2792 static void
2793 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value)
2794 {
2795         int card_table_shift_bits;
2796         gpointer card_table_mask;
2797         guint8 *card_table;
2798         MonoInst *dummy_use;
2799         int nursery_shift_bits;
2800         size_t nursery_size;
2801         gboolean has_card_table_wb = FALSE;
2802
2803         if (!cfg->gen_write_barriers)
2804                 return;
2805
2806         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2807
2808         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2809
2810 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
2811         has_card_table_wb = TRUE;
2812 #endif
2813
2814         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0) {
2815                 MonoInst *wbarrier;
2816
2817                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2818                 wbarrier->sreg1 = ptr->dreg;
2819                 wbarrier->sreg2 = value->dreg;
2820                 MONO_ADD_INS (cfg->cbb, wbarrier);
2821         } else if (card_table) {
2822                 int offset_reg = alloc_preg (cfg);
2823                 int card_reg  = alloc_preg (cfg);
2824                 MonoInst *ins;
2825
2826                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2827                 if (card_table_mask)
2828                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2829
2830                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2831                  * IMM's larger than 32bits.
2832                  */
2833                 if (cfg->compile_aot) {
2834                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
2835                 } else {
2836                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2837                         ins->inst_p0 = card_table;
2838                         ins->dreg = card_reg;
2839                         MONO_ADD_INS (cfg->cbb, ins);
2840                 }
2841
2842                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2843                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2844         } else {
2845                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2846                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
2847         }
2848
2849         EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
2850 }
2851
2852 static gboolean
2853 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
2854 {
2855         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
2856         unsigned need_wb = 0;
2857
2858         if (align == 0)
2859                 align = 4;
2860
2861         /*types with references can't have alignment smaller than sizeof(void*) */
2862         if (align < SIZEOF_VOID_P)
2863                 return FALSE;
2864
2865         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
2866         if (size > 32 * SIZEOF_VOID_P)
2867                 return FALSE;
2868
2869         create_write_barrier_bitmap (cfg, klass, &need_wb, 0);
2870
2871         /* We don't unroll more than 5 stores to avoid code bloat. */
2872         if (size > 5 * SIZEOF_VOID_P) {
2873                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
2874                 size += (SIZEOF_VOID_P - 1);
2875                 size &= ~(SIZEOF_VOID_P - 1);
2876
2877                 EMIT_NEW_ICONST (cfg, iargs [2], size);
2878                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
2879                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
2880                 return TRUE;
2881         }
2882
2883         destreg = iargs [0]->dreg;
2884         srcreg = iargs [1]->dreg;
2885         offset = 0;
2886
2887         dest_ptr_reg = alloc_preg (cfg);
2888         tmp_reg = alloc_preg (cfg);
2889
2890         /*tmp = dreg*/
2891         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
2892
2893         while (size >= SIZEOF_VOID_P) {
2894                 MonoInst *load_inst;
2895                 MONO_INST_NEW (cfg, load_inst, OP_LOAD_MEMBASE);
2896                 load_inst->dreg = tmp_reg;
2897                 load_inst->inst_basereg = srcreg;
2898                 load_inst->inst_offset = offset;
2899                 MONO_ADD_INS (cfg->cbb, load_inst);
2900
2901                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
2902
2903                 if (need_wb & 0x1)
2904                         emit_write_barrier (cfg, iargs [0], load_inst);
2905
2906                 offset += SIZEOF_VOID_P;
2907                 size -= SIZEOF_VOID_P;
2908                 need_wb >>= 1;
2909
2910                 /*tmp += sizeof (void*)*/
2911                 if (size >= SIZEOF_VOID_P) {
2912                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
2913                         MONO_ADD_INS (cfg->cbb, iargs [0]);
2914                 }
2915         }
2916
2917         /* Those cannot be references since size < sizeof (void*) */
2918         while (size >= 4) {
2919                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
2920                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
2921                 offset += 4;
2922                 size -= 4;
2923         }
2924
2925         while (size >= 2) {
2926                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
2927                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
2928                 offset += 2;
2929                 size -= 2;
2930         }
2931
2932         while (size >= 1) {
2933                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
2934                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
2935                 offset += 1;
2936                 size -= 1;
2937         }
2938
2939         return TRUE;
2940 }
2941
2942 /*
2943  * Emit code to copy a valuetype of type @klass whose address is stored in
2944  * @src->dreg to memory whose address is stored at @dest->dreg.
2945  */
2946 void
2947 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
2948 {
2949         MonoInst *iargs [4];
2950         int context_used, n;
2951         guint32 align = 0;
2952         MonoMethod *memcpy_method;
2953         MonoInst *size_ins = NULL;
2954         MonoInst *memcpy_ins = NULL;
2955
2956         g_assert (klass);
2957         /*
2958          * This check breaks with spilled vars... need to handle it during verification anyway.
2959          * g_assert (klass && klass == src->klass && klass == dest->klass);
2960          */
2961
2962         if (mini_is_gsharedvt_klass (cfg, klass)) {
2963                 g_assert (!native);
2964                 context_used = mini_class_check_context_used (cfg, klass);
2965                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
2966                 memcpy_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_MEMCPY);
2967         }
2968
2969         if (native)
2970                 n = mono_class_native_size (klass, &align);
2971         else
2972                 n = mono_class_value_size (klass, &align);
2973
2974         /* if native is true there should be no references in the struct */
2975         if (cfg->gen_write_barriers && (klass->has_references || size_ins) && !native) {
2976                 /* Avoid barriers when storing to the stack */
2977                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
2978                           (dest->opcode == OP_LDADDR))) {
2979                         int context_used;
2980
2981                         iargs [0] = dest;
2982                         iargs [1] = src;
2983
2984                         context_used = mini_class_check_context_used (cfg, klass);
2985
2986                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
2987                         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
2988                                 return;
2989                         } else if (context_used) {
2990                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
2991                         }  else {
2992                                 if (cfg->compile_aot) {
2993                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
2994                                 } else {
2995                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
2996                                         mono_class_compute_gc_descriptor (klass);
2997                                 }
2998                         }
2999
3000                         if (size_ins)
3001                                 mono_emit_jit_icall (cfg, mono_gsharedvt_value_copy, iargs);
3002                         else
3003                                 mono_emit_jit_icall (cfg, mono_value_copy, iargs);
3004                         return;
3005                 }
3006         }
3007
3008         if (!size_ins && (cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
3009                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
3010                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
3011         } else {
3012                 iargs [0] = dest;
3013                 iargs [1] = src;
3014                 if (size_ins)
3015                         iargs [2] = size_ins;
3016                 else
3017                         EMIT_NEW_ICONST (cfg, iargs [2], n);
3018                 
3019                 memcpy_method = get_memcpy_method ();
3020                 if (memcpy_ins)
3021                         mono_emit_calli (cfg, mono_method_signature (memcpy_method), iargs, memcpy_ins, NULL, NULL);
3022                 else
3023                         mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
3024         }
3025 }
3026
3027 static MonoMethod*
3028 get_memset_method (void)
3029 {
3030         static MonoMethod *memset_method = NULL;
3031         if (!memset_method) {
3032                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
3033                 if (!memset_method)
3034                         g_error ("Old corlib found. Install a new one");
3035         }
3036         return memset_method;
3037 }
3038
3039 void
3040 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
3041 {
3042         MonoInst *iargs [3];
3043         int n, context_used;
3044         guint32 align;
3045         MonoMethod *memset_method;
3046         MonoInst *size_ins = NULL;
3047         MonoInst *bzero_ins = NULL;
3048         static MonoMethod *bzero_method;
3049
3050         /* FIXME: Optimize this for the case when dest is an LDADDR */
3051
3052         mono_class_init (klass);
3053         if (mini_is_gsharedvt_klass (cfg, klass)) {
3054                 context_used = mini_class_check_context_used (cfg, klass);
3055                 size_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_VALUE_SIZE);
3056                 bzero_ins = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_BZERO);
3057                 if (!bzero_method)
3058                         bzero_method = mono_class_get_method_from_name (mono_defaults.string_class, "bzero_aligned_1", 2);
3059                 g_assert (bzero_method);
3060                 iargs [0] = dest;
3061                 iargs [1] = size_ins;
3062                 mono_emit_calli (cfg, mono_method_signature (bzero_method), iargs, bzero_ins, NULL, NULL);
3063                 return;
3064         }
3065
3066         n = mono_class_value_size (klass, &align);
3067
3068         if (n <= sizeof (gpointer) * 5) {
3069                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
3070         }
3071         else {
3072                 memset_method = get_memset_method ();
3073                 iargs [0] = dest;
3074                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
3075                 EMIT_NEW_ICONST (cfg, iargs [2], n);
3076                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
3077         }
3078 }
3079
3080 static MonoInst*
3081 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
3082 {
3083         MonoInst *this = NULL;
3084
3085         g_assert (cfg->generic_sharing_context);
3086
3087         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
3088                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
3089                         !method->klass->valuetype)
3090                 EMIT_NEW_ARGLOAD (cfg, this, 0);
3091
3092         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
3093                 MonoInst *mrgctx_loc, *mrgctx_var;
3094
3095                 g_assert (!this);
3096                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
3097
3098                 mrgctx_loc = mono_get_vtable_var (cfg);
3099                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
3100
3101                 return mrgctx_var;
3102         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
3103                 MonoInst *vtable_loc, *vtable_var;
3104
3105                 g_assert (!this);
3106
3107                 vtable_loc = mono_get_vtable_var (cfg);
3108                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
3109
3110                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
3111                         MonoInst *mrgctx_var = vtable_var;
3112                         int vtable_reg;
3113
3114                         vtable_reg = alloc_preg (cfg);
3115                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
3116                         vtable_var->type = STACK_PTR;
3117                 }
3118
3119                 return vtable_var;
3120         } else {
3121                 MonoInst *ins;
3122                 int vtable_reg;
3123         
3124                 vtable_reg = alloc_preg (cfg);
3125                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3126                 return ins;
3127         }
3128 }
3129
3130 static MonoJumpInfoRgctxEntry *
3131 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, MonoRgctxInfoType info_type)
3132 {
3133         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
3134         res->method = method;
3135         res->in_mrgctx = in_mrgctx;
3136         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
3137         res->data->type = patch_type;
3138         res->data->data.target = patch_data;
3139         res->info_type = info_type;
3140
3141         return res;
3142 }
3143
3144 static inline MonoInst*
3145 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
3146 {
3147         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
3148 }
3149
3150 static MonoInst*
3151 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
3152                                           MonoClass *klass, MonoRgctxInfoType rgctx_type)
3153 {
3154         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);
3155         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3156
3157         return emit_rgctx_fetch (cfg, rgctx, entry);
3158 }
3159
3160 static MonoInst*
3161 emit_get_rgctx_sig (MonoCompile *cfg, int context_used,
3162                                         MonoMethodSignature *sig, MonoRgctxInfoType rgctx_type)
3163 {
3164         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);
3165         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3166
3167         return emit_rgctx_fetch (cfg, rgctx, entry);
3168 }
3169
3170 static MonoInst*
3171 emit_get_rgctx_gsharedvt_call (MonoCompile *cfg, int context_used,
3172                                                            MonoMethodSignature *sig, MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3173 {
3174         MonoJumpInfoGSharedVtCall *call_info;
3175         MonoJumpInfoRgctxEntry *entry;
3176         MonoInst *rgctx;
3177
3178         call_info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoGSharedVtCall));
3179         call_info->sig = sig;
3180         call_info->method = cmethod;
3181
3182         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);
3183         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3184
3185         return emit_rgctx_fetch (cfg, rgctx, entry);
3186 }
3187
3188
3189 static MonoInst*
3190 emit_get_rgctx_gsharedvt_method (MonoCompile *cfg, int context_used,
3191                                                                  MonoMethod *cmethod, MonoGSharedVtMethodInfo *info)
3192 {
3193         MonoJumpInfoRgctxEntry *entry;
3194         MonoInst *rgctx;
3195
3196         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);
3197         rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3198
3199         return emit_rgctx_fetch (cfg, rgctx, entry);
3200 }
3201
3202 /*
3203  * emit_get_rgctx_method:
3204  *
3205  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
3206  * normal constants, else emit a load from the rgctx.
3207  */
3208 static MonoInst*
3209 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
3210                                            MonoMethod *cmethod, MonoRgctxInfoType rgctx_type)
3211 {
3212         if (!context_used) {
3213                 MonoInst *ins;
3214
3215                 switch (rgctx_type) {
3216                 case MONO_RGCTX_INFO_METHOD:
3217                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
3218                         return ins;
3219                 case MONO_RGCTX_INFO_METHOD_RGCTX:
3220                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
3221                         return ins;
3222                 default:
3223                         g_assert_not_reached ();
3224                 }
3225         } else {
3226                 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);
3227                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3228
3229                 return emit_rgctx_fetch (cfg, rgctx, entry);
3230         }
3231 }
3232
3233 static MonoInst*
3234 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
3235                                           MonoClassField *field, MonoRgctxInfoType rgctx_type)
3236 {
3237         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);
3238         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3239
3240         return emit_rgctx_fetch (cfg, rgctx, entry);
3241 }
3242
3243 static int
3244 get_gsharedvt_info_slot (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3245 {
3246         MonoGSharedVtMethodInfo *info = cfg->gsharedvt_info;
3247         MonoRuntimeGenericContextInfoTemplate *template;
3248         int i, idx;
3249
3250         g_assert (info);
3251
3252         for (i = 0; i < info->entries->len; ++i) {
3253                 MonoRuntimeGenericContextInfoTemplate *otemplate = g_ptr_array_index (info->entries, i);
3254
3255                 if (otemplate->info_type == rgctx_type && otemplate->data == data && rgctx_type != MONO_RGCTX_INFO_LOCAL_OFFSET)
3256                         return i;
3257         }
3258
3259         template = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoRuntimeGenericContextInfoTemplate));
3260         template->info_type = rgctx_type;
3261         template->data = data;
3262
3263         idx = info->entries->len;
3264
3265         g_ptr_array_add (info->entries, template);
3266
3267         return idx;
3268 }
3269
3270 /*
3271  * emit_get_gsharedvt_info:
3272  *
3273  *   This is similar to emit_get_rgctx_.., but loads the data from the gsharedvt info var instead of calling an rgctx fetch trampoline.
3274  */
3275 static MonoInst*
3276 emit_get_gsharedvt_info (MonoCompile *cfg, gpointer data, MonoRgctxInfoType rgctx_type)
3277 {
3278         MonoInst *ins;
3279         int idx, dreg;
3280
3281         idx = get_gsharedvt_info_slot (cfg, data, rgctx_type);
3282         /* Load info->entries [idx] */
3283         dreg = alloc_preg (cfg);
3284         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, cfg->gsharedvt_info_var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
3285
3286         return ins;
3287 }
3288
3289 static MonoInst*
3290 emit_get_gsharedvt_info_klass (MonoCompile *cfg, MonoClass *klass, MonoRgctxInfoType rgctx_type)
3291 {
3292         return emit_get_gsharedvt_info (cfg, &klass->byval_arg, rgctx_type);
3293 }
3294
3295 /*
3296  * On return the caller must check @klass for load errors.
3297  */
3298 static void
3299 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
3300 {
3301         MonoInst *vtable_arg;
3302         MonoCallInst *call;
3303         int context_used;
3304
3305         context_used = mini_class_check_context_used (cfg, klass);
3306
3307         if (context_used) {
3308                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
3309                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
3310         } else {
3311                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3312
3313                 if (!vtable)
3314                         return;
3315                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3316         }
3317
3318         if (COMPILE_LLVM (cfg))
3319                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3320         else
3321                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3322 #ifdef MONO_ARCH_VTABLE_REG
3323         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3324         cfg->uses_vtable_reg = TRUE;
3325 #else
3326         NOT_IMPLEMENTED;
3327 #endif
3328 }
3329
3330 static void
3331 emit_seq_point (MonoCompile *cfg, MonoMethod *method, guint8* ip, gboolean intr_loc, gboolean nonempty_stack)
3332 {
3333         MonoInst *ins;
3334
3335         if (cfg->gen_seq_points && cfg->method == method) {
3336                 NEW_SEQ_POINT (cfg, ins, ip - cfg->header->code, intr_loc);
3337                 if (nonempty_stack)
3338                         ins->flags |= MONO_INST_NONEMPTY_STACK;
3339                 MONO_ADD_INS (cfg->cbb, ins);
3340         }
3341 }
3342
3343 static void
3344 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg, gboolean null_check, MonoBasicBlock **out_bblock)
3345 {
3346         if (mini_get_debug_options ()->better_cast_details) {
3347                 int to_klass_reg = alloc_preg (cfg);
3348                 int vtable_reg = alloc_preg (cfg);
3349                 int klass_reg = alloc_preg (cfg);
3350                 MonoBasicBlock *is_null_bb = NULL;
3351                 MonoInst *tls_get;
3352
3353                 if (null_check) {
3354                         NEW_BBLOCK (cfg, is_null_bb);
3355
3356                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3357                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3358                 }
3359
3360                 tls_get = mono_get_jit_tls_intrinsic (cfg);
3361                 if (!tls_get) {
3362                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3363                         exit (1);
3364                 }
3365
3366                 MONO_ADD_INS (cfg->cbb, tls_get);
3367                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3368                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3369
3370                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3371                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3372                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3373
3374                 if (null_check) {
3375                         MONO_START_BB (cfg, is_null_bb);
3376                         if (out_bblock)
3377                                 *out_bblock = cfg->cbb;
3378                 }
3379         }
3380 }
3381
3382 static void
3383 reset_cast_details (MonoCompile *cfg)
3384 {
3385         /* Reset the variables holding the cast details */
3386         if (mini_get_debug_options ()->better_cast_details) {
3387                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3388
3389                 MONO_ADD_INS (cfg->cbb, tls_get);
3390                 /* It is enough to reset the from field */
3391                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3392         }
3393 }
3394
3395 /*
3396  * On return the caller must check @array_class for load errors
3397  */
3398 static void
3399 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3400 {
3401         int vtable_reg = alloc_preg (cfg);
3402         int context_used;
3403
3404         context_used = mini_class_check_context_used (cfg, array_class);
3405
3406         save_cast_details (cfg, array_class, obj->dreg, FALSE, NULL);
3407
3408         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3409
3410         if (cfg->opt & MONO_OPT_SHARED) {
3411                 int class_reg = alloc_preg (cfg);
3412                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3413                 if (cfg->compile_aot) {
3414                         int klass_reg = alloc_preg (cfg);
3415                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3416                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3417                 } else {
3418                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3419                 }
3420         } else if (context_used) {
3421                 MonoInst *vtable_ins;
3422
3423                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3424                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3425         } else {
3426                 if (cfg->compile_aot) {
3427                         int vt_reg;
3428                         MonoVTable *vtable;
3429
3430                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3431                                 return;
3432                         vt_reg = alloc_preg (cfg);
3433                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3434                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3435                 } else {
3436                         MonoVTable *vtable;
3437                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3438                                 return;
3439                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3440                 }
3441         }
3442         
3443         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3444
3445         reset_cast_details (cfg);
3446 }
3447
3448 /**
3449  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3450  * generic code is generated.
3451  */
3452 static MonoInst*
3453 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3454 {
3455         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3456
3457         if (context_used) {
3458                 MonoInst *rgctx, *addr;
3459
3460                 /* FIXME: What if the class is shared?  We might not
3461                    have to get the address of the method from the
3462                    RGCTX. */
3463                 addr = emit_get_rgctx_method (cfg, context_used, method,
3464                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3465
3466                 rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3467
3468                 return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3469         } else {
3470                 gboolean pass_vtable, pass_mrgctx;
3471                 MonoInst *rgctx_arg = NULL;
3472
3473                 check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3474                 g_assert (!pass_mrgctx);
3475
3476                 if (pass_vtable) {
3477                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3478
3479                         g_assert (vtable);
3480                         EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3481                 }
3482
3483                 return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3484         }
3485 }
3486
3487 static MonoInst*
3488 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3489 {
3490         MonoInst *add;
3491         int obj_reg;
3492         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3493         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3494         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3495         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3496
3497         obj_reg = sp [0]->dreg;
3498         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3499         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3500
3501         /* FIXME: generics */
3502         g_assert (klass->rank == 0);
3503                         
3504         // Check rank == 0
3505         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3506         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3507
3508         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3509         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3510
3511         if (context_used) {
3512                 MonoInst *element_class;
3513
3514                 /* This assertion is from the unboxcast insn */
3515                 g_assert (klass->rank == 0);
3516
3517                 element_class = emit_get_rgctx_klass (cfg, context_used,
3518                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3519
3520                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3521                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3522         } else {
3523                 save_cast_details (cfg, klass->element_class, obj_reg, FALSE, NULL);
3524                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3525                 reset_cast_details (cfg);
3526         }
3527
3528         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), obj_reg, sizeof (MonoObject));
3529         MONO_ADD_INS (cfg->cbb, add);
3530         add->type = STACK_MP;
3531         add->klass = klass;
3532
3533         return add;
3534 }
3535
3536 static MonoInst*
3537 handle_unbox_gsharedvt (MonoCompile *cfg, MonoClass *klass, MonoInst *obj, MonoBasicBlock **out_cbb)
3538 {
3539         MonoInst *addr, *klass_inst, *is_ref, *args[16];
3540         MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3541         MonoInst *ins;
3542         int dreg, addr_reg;
3543
3544         klass_inst = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_KLASS);
3545
3546         /* obj */
3547         args [0] = obj;
3548
3549         /* klass */
3550         args [1] = klass_inst;
3551
3552         /* CASTCLASS */
3553         obj = mono_emit_jit_icall (cfg, mono_object_castclass_unbox, args);
3554
3555         NEW_BBLOCK (cfg, is_ref_bb);
3556         NEW_BBLOCK (cfg, is_nullable_bb);
3557         NEW_BBLOCK (cfg, end_bb);
3558         is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3559         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3560         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3561
3562         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3563         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3564
3565         /* This will contain either the address of the unboxed vtype, or an address of the temporary where the ref is stored */
3566         addr_reg = alloc_dreg (cfg, STACK_MP);
3567
3568         /* Non-ref case */
3569         /* UNBOX */
3570         NEW_BIALU_IMM (cfg, addr, OP_ADD_IMM, addr_reg, obj->dreg, sizeof (MonoObject));
3571         MONO_ADD_INS (cfg->cbb, addr);
3572
3573         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3574
3575         /* Ref case */
3576         MONO_START_BB (cfg, is_ref_bb);
3577
3578         /* Save the ref to a temporary */
3579         dreg = alloc_ireg (cfg);
3580         EMIT_NEW_VARLOADA_VREG (cfg, addr, dreg, &klass->byval_arg);
3581         addr->dreg = addr_reg;
3582         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, obj->dreg);
3583         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3584
3585         /* Nullable case */
3586         MONO_START_BB (cfg, is_nullable_bb);
3587
3588         {
3589                 MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_NULLABLE_CLASS_UNBOX);
3590                 MonoInst *unbox_call;
3591                 MonoMethodSignature *unbox_sig;
3592                 MonoInst *var;
3593
3594                 var = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
3595
3596                 unbox_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3597                 unbox_sig->ret = &klass->byval_arg;
3598                 unbox_sig->param_count = 1;
3599                 unbox_sig->params [0] = &mono_defaults.object_class->byval_arg;
3600                 unbox_call = mono_emit_calli (cfg, unbox_sig, &obj, addr, NULL, NULL);
3601
3602                 EMIT_NEW_VARLOADA_VREG (cfg, addr, unbox_call->dreg, &klass->byval_arg);
3603                 addr->dreg = addr_reg;
3604         }
3605
3606         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3607
3608         /* End */
3609         MONO_START_BB (cfg, end_bb);
3610
3611         /* LDOBJ */
3612         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr_reg, 0);
3613
3614         *out_cbb = cfg->cbb;
3615
3616         return ins;
3617 }
3618
3619 /*
3620  * Returns NULL and set the cfg exception on error.
3621  */
3622 static MonoInst*
3623 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3624 {
3625         MonoInst *iargs [2];
3626         void *alloc_ftn;
3627
3628         if (context_used) {
3629                 MonoInst *data;
3630                 int rgctx_info;
3631                 MonoInst *iargs [2];
3632
3633                 MonoMethod *managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3634
3635                 if (cfg->opt & MONO_OPT_SHARED)
3636                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3637                 else
3638                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3639                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3640
3641                 if (cfg->opt & MONO_OPT_SHARED) {
3642                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3643                         iargs [1] = data;
3644                         alloc_ftn = mono_object_new;
3645                 } else {
3646                         iargs [0] = data;
3647                         alloc_ftn = mono_object_new_specific;
3648                 }
3649
3650                 if (managed_alloc && !(cfg->opt & MONO_OPT_SHARED))
3651                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3652
3653                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3654         }
3655
3656         if (cfg->opt & MONO_OPT_SHARED) {
3657                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3658                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3659
3660                 alloc_ftn = mono_object_new;
3661         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3662                 /* This happens often in argument checking code, eg. throw new FooException... */
3663                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3664                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3665                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3666         } else {
3667                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3668                 MonoMethod *managed_alloc = NULL;
3669                 gboolean pass_lw;
3670
3671                 if (!vtable) {
3672                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3673                         cfg->exception_ptr = klass;
3674                         return NULL;
3675                 }
3676
3677 #ifndef MONO_CROSS_COMPILE
3678                 managed_alloc = mono_gc_get_managed_allocator (klass, for_box);
3679 #endif
3680
3681                 if (managed_alloc) {
3682                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3683                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3684                 }
3685                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3686                 if (pass_lw) {
3687                         guint32 lw = vtable->klass->instance_size;
3688                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3689                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3690                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3691                 }
3692                 else {
3693                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3694                 }
3695         }
3696
3697         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3698 }
3699         
3700 /*
3701  * Returns NULL and set the cfg exception on error.
3702  */     
3703 static MonoInst*
3704 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used, MonoBasicBlock **out_cbb)
3705 {
3706         MonoInst *alloc, *ins;
3707
3708         *out_cbb = cfg->cbb;
3709
3710         if (mono_class_is_nullable (klass)) {
3711                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3712
3713                 if (context_used) {
3714                         /* FIXME: What if the class is shared?  We might not
3715                            have to get the method address from the RGCTX. */
3716                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3717                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3718                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3719
3720                         return mono_emit_calli (cfg, mono_method_signature (method), &val, addr, NULL, rgctx);
3721                 } else {
3722                         gboolean pass_vtable, pass_mrgctx;
3723                         MonoInst *rgctx_arg = NULL;
3724
3725                         check_method_sharing (cfg, method, &pass_vtable, &pass_mrgctx);
3726                         g_assert (!pass_mrgctx);
3727
3728                         if (pass_vtable) {
3729                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
3730
3731                                 g_assert (vtable);
3732                                 EMIT_NEW_VTABLECONST (cfg, rgctx_arg, vtable);
3733                         }
3734
3735                         return mono_emit_method_call_full (cfg, method, NULL, FALSE, &val, NULL, NULL, rgctx_arg);
3736                 }
3737         }
3738
3739         if (mini_is_gsharedvt_klass (cfg, klass)) {
3740                 MonoBasicBlock *is_ref_bb, *is_nullable_bb, *end_bb;
3741                 MonoInst *res, *is_ref, *src_var, *addr;
3742                 int addr_reg, dreg;
3743
3744                 dreg = alloc_ireg (cfg);
3745
3746                 NEW_BBLOCK (cfg, is_ref_bb);
3747                 NEW_BBLOCK (cfg, is_nullable_bb);
3748                 NEW_BBLOCK (cfg, end_bb);
3749                 is_ref = emit_get_gsharedvt_info_klass (cfg, klass, MONO_RGCTX_INFO_CLASS_BOX_TYPE);
3750                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 1);
3751                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_ref_bb);
3752
3753                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, is_ref->dreg, 2);
3754                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_nullable_bb);
3755
3756                 /* Non-ref case */
3757                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3758                 if (!alloc)
3759                         return NULL;
3760                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3761                 ins->opcode = OP_STOREV_MEMBASE;
3762
3763                 EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, alloc->dreg);
3764                 res->type = STACK_OBJ;
3765                 res->klass = klass;
3766                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3767                 
3768                 /* Ref case */
3769                 MONO_START_BB (cfg, is_ref_bb);
3770                 addr_reg = alloc_ireg (cfg);
3771
3772                 /* val is a vtype, so has to load the value manually */
3773                 src_var = get_vreg_to_inst (cfg, val->dreg);
3774                 if (!src_var)
3775                         src_var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, val->dreg);
3776                 EMIT_NEW_VARLOADA (cfg, addr, src_var, src_var->inst_vtype);
3777                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, addr->dreg, 0);
3778                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3779
3780                 /* Nullable case */
3781                 MONO_START_BB (cfg, is_nullable_bb);
3782
3783                 {
3784                         MonoInst *addr = emit_get_gsharedvt_info_klass (cfg, klass,
3785                                                                                                         MONO_RGCTX_INFO_NULLABLE_CLASS_BOX);
3786                         MonoInst *box_call;
3787                         MonoMethodSignature *box_sig;
3788
3789                         /*
3790                          * klass is Nullable<T>, need to call Nullable<T>.Box () using a gsharedvt signature, but we cannot
3791                          * construct that method at JIT time, so have to do things by hand.
3792                          */
3793                         box_sig = mono_mempool_alloc0 (cfg->mempool, MONO_SIZEOF_METHOD_SIGNATURE + (1 * sizeof (MonoType *)));
3794                         box_sig->ret = &mono_defaults.object_class->byval_arg;
3795                         box_sig->param_count = 1;
3796                         box_sig->params [0] = &klass->byval_arg;
3797                         box_call = mono_emit_calli (cfg, box_sig, &val, addr, NULL, NULL);
3798                         EMIT_NEW_UNALU (cfg, res, OP_MOVE, dreg, box_call->dreg);
3799                         res->type = STACK_OBJ;
3800                         res->klass = klass;
3801                 }
3802
3803                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3804
3805                 MONO_START_BB (cfg, end_bb);
3806
3807                 *out_cbb = cfg->cbb;
3808
3809                 return res;
3810         } else {
3811                 alloc = handle_alloc (cfg, klass, TRUE, context_used);
3812                 if (!alloc)
3813                         return NULL;
3814
3815                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3816                 return alloc;
3817         }
3818 }
3819
3820
3821 static gboolean
3822 mini_class_has_reference_variant_generic_argument (MonoCompile *cfg, MonoClass *klass, int context_used)
3823 {
3824         int i;
3825         MonoGenericContainer *container;
3826         MonoGenericInst *ginst;
3827
3828         if (klass->generic_class) {
3829                 container = klass->generic_class->container_class->generic_container;
3830                 ginst = klass->generic_class->context.class_inst;
3831         } else if (klass->generic_container && context_used) {
3832                 container = klass->generic_container;
3833                 ginst = container->context.class_inst;
3834         } else {
3835                 return FALSE;
3836         }
3837
3838         for (i = 0; i < container->type_argc; ++i) {
3839                 MonoType *type;
3840                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
3841                         continue;
3842                 type = ginst->type_argv [i];
3843                 if (mini_type_is_reference (cfg, type))
3844                         return TRUE;
3845         }
3846         return FALSE;
3847 }
3848
3849 // FIXME: This doesn't work yet (class libs tests fail?)
3850 #define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || mono_class_is_marshalbyref (klass) || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
3851
3852 /*
3853  * Returns NULL and set the cfg exception on error.
3854  */
3855 static MonoInst*
3856 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3857 {
3858         MonoBasicBlock *is_null_bb;
3859         int obj_reg = src->dreg;
3860         int vtable_reg = alloc_preg (cfg);
3861         MonoInst *klass_inst = NULL;
3862
3863         if (context_used) {
3864                 MonoInst *args [3];
3865
3866                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
3867                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
3868                         MonoInst *cache_ins;
3869
3870                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
3871
3872                         /* obj */
3873                         args [0] = src;
3874
3875                         /* klass - it's the second element of the cache entry*/
3876                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
3877
3878                         /* cache */
3879                         args [2] = cache_ins;
3880
3881                         return mono_emit_method_call (cfg, mono_castclass, args, NULL);
3882                 }
3883
3884                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3885         }
3886
3887         NEW_BBLOCK (cfg, is_null_bb);
3888
3889         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3890         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3891
3892         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
3893
3894         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3895                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3896                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
3897         } else {
3898                 int klass_reg = alloc_preg (cfg);
3899
3900                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3901
3902                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
3903                         /* the remoting code is broken, access the class for now */
3904                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
3905                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
3906                                 if (!vt) {
3907                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3908                                         cfg->exception_ptr = klass;
3909                                         return NULL;
3910                                 }
3911                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
3912                         } else {
3913                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3914                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
3915                         }
3916                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3917                 } else {
3918                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3919                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
3920                 }
3921         }
3922
3923         MONO_START_BB (cfg, is_null_bb);
3924
3925         reset_cast_details (cfg);
3926
3927         return src;
3928 }
3929
3930 /*
3931  * Returns NULL and set the cfg exception on error.
3932  */
3933 static MonoInst*
3934 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3935 {
3936         MonoInst *ins;
3937         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
3938         int obj_reg = src->dreg;
3939         int vtable_reg = alloc_preg (cfg);
3940         int res_reg = alloc_ireg_ref (cfg);
3941         MonoInst *klass_inst = NULL;
3942
3943         if (context_used) {
3944                 MonoInst *args [3];
3945
3946                 if(mini_class_has_reference_variant_generic_argument (cfg, klass, context_used) || is_complex_isinst (klass)) {
3947                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
3948                         MonoInst *cache_ins;
3949
3950                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
3951
3952                         /* obj */
3953                         args [0] = src;
3954
3955                         /* klass - it's the second element of the cache entry*/
3956                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
3957
3958                         /* cache */
3959                         args [2] = cache_ins;
3960
3961                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
3962                 }
3963
3964                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3965         }
3966
3967         NEW_BBLOCK (cfg, is_null_bb);
3968         NEW_BBLOCK (cfg, false_bb);
3969         NEW_BBLOCK (cfg, end_bb);
3970
3971         /* Do the assignment at the beginning, so the other assignment can be if converted */
3972         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
3973         ins->type = STACK_OBJ;
3974         ins->klass = klass;
3975
3976         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3977         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
3978
3979         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3980
3981         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3982                 g_assert (!context_used);
3983                 /* the is_null_bb target simply copies the input register to the output */
3984                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
3985         } else {
3986                 int klass_reg = alloc_preg (cfg);
3987
3988                 if (klass->rank) {
3989                         int rank_reg = alloc_preg (cfg);
3990                         int eclass_reg = alloc_preg (cfg);
3991
3992                         g_assert (!context_used);
3993                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3994                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
3995                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
3996                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3997                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
3998                         if (klass->cast_class == mono_defaults.object_class) {
3999                                 int parent_reg = alloc_preg (cfg);
4000                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
4001                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
4002                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4003                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4004                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
4005                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
4006                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
4007                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4008                         } else if (klass->cast_class == mono_defaults.enum_class) {
4009                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
4010                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
4011                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
4012                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4013                         } else {
4014                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
4015                                         /* Check that the object is a vector too */
4016                                         int bounds_reg = alloc_preg (cfg);
4017                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
4018                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4019                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4020                                 }
4021
4022                                 /* the is_null_bb target simply copies the input register to the output */
4023                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
4024                         }
4025                 } else if (mono_class_is_nullable (klass)) {
4026                         g_assert (!context_used);
4027                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4028                         /* the is_null_bb target simply copies the input register to the output */
4029                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
4030                 } else {
4031                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
4032                                 g_assert (!context_used);
4033                                 /* the remoting code is broken, access the class for now */
4034                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
4035                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
4036                                         if (!vt) {
4037                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
4038                                                 cfg->exception_ptr = klass;
4039                                                 return NULL;
4040                                         }
4041                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
4042                                 } else {
4043                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4044                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
4045                                 }
4046                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
4047                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
4048                         } else {
4049                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4050                                 /* the is_null_bb target simply copies the input register to the output */
4051                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
4052                         }
4053                 }
4054         }
4055
4056         MONO_START_BB (cfg, false_bb);
4057
4058         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
4059         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4060
4061         MONO_START_BB (cfg, is_null_bb);
4062
4063         MONO_START_BB (cfg, end_bb);
4064
4065         return ins;
4066 }
4067
4068 static MonoInst*
4069 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4070 {
4071         /* This opcode takes as input an object reference and a class, and returns:
4072         0) if the object is an instance of the class,
4073         1) if the object is not instance of the class,
4074         2) if the object is a proxy whose type cannot be determined */
4075
4076         MonoInst *ins;
4077 #ifndef DISABLE_REMOTING
4078         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
4079 #else
4080         MonoBasicBlock *true_bb, *false_bb, *end_bb;
4081 #endif
4082         int obj_reg = src->dreg;
4083         int dreg = alloc_ireg (cfg);
4084         int tmp_reg;
4085 #ifndef DISABLE_REMOTING
4086         int klass_reg = alloc_preg (cfg);
4087 #endif
4088
4089         NEW_BBLOCK (cfg, true_bb);
4090         NEW_BBLOCK (cfg, false_bb);
4091         NEW_BBLOCK (cfg, end_bb);
4092 #ifndef DISABLE_REMOTING
4093         NEW_BBLOCK (cfg, false2_bb);
4094         NEW_BBLOCK (cfg, no_proxy_bb);
4095 #endif
4096
4097         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4098         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
4099
4100         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4101 #ifndef DISABLE_REMOTING
4102                 NEW_BBLOCK (cfg, interface_fail_bb);
4103 #endif
4104
4105                 tmp_reg = alloc_preg (cfg);
4106                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4107 #ifndef DISABLE_REMOTING
4108                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
4109                 MONO_START_BB (cfg, interface_fail_bb);
4110                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4111                 
4112                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
4113
4114                 tmp_reg = alloc_preg (cfg);
4115                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4116                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4117                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
4118 #else
4119                 mini_emit_iface_cast (cfg, tmp_reg, klass, false_bb, true_bb);
4120 #endif
4121         } else {
4122 #ifndef DISABLE_REMOTING
4123                 tmp_reg = alloc_preg (cfg);
4124                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4125                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4126
4127                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4128                 tmp_reg = alloc_preg (cfg);
4129                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4130                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4131
4132                 tmp_reg = alloc_preg (cfg);             
4133                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4134                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4135                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4136                 
4137                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
4138                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
4139
4140                 MONO_START_BB (cfg, no_proxy_bb);
4141
4142                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
4143 #else
4144                 g_error ("transparent proxy support is disabled while trying to JIT code that uses it");
4145 #endif
4146         }
4147
4148         MONO_START_BB (cfg, false_bb);
4149
4150         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4151         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4152
4153 #ifndef DISABLE_REMOTING
4154         MONO_START_BB (cfg, false2_bb);
4155
4156         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
4157         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4158 #endif
4159
4160         MONO_START_BB (cfg, true_bb);
4161
4162         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4163
4164         MONO_START_BB (cfg, end_bb);
4165
4166         /* FIXME: */
4167         MONO_INST_NEW (cfg, ins, OP_ICONST);
4168         ins->dreg = dreg;
4169         ins->type = STACK_I4;
4170
4171         return ins;
4172 }
4173
4174 static MonoInst*
4175 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
4176 {
4177         /* This opcode takes as input an object reference and a class, and returns:
4178         0) if the object is an instance of the class,
4179         1) if the object is a proxy whose type cannot be determined
4180         an InvalidCastException exception is thrown otherwhise*/
4181         
4182         MonoInst *ins;
4183 #ifndef DISABLE_REMOTING
4184         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
4185 #else
4186         MonoBasicBlock *ok_result_bb;
4187 #endif
4188         int obj_reg = src->dreg;
4189         int dreg = alloc_ireg (cfg);
4190         int tmp_reg = alloc_preg (cfg);
4191
4192 #ifndef DISABLE_REMOTING
4193         int klass_reg = alloc_preg (cfg);
4194         NEW_BBLOCK (cfg, end_bb);
4195 #endif
4196
4197         NEW_BBLOCK (cfg, ok_result_bb);
4198
4199         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
4200         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
4201
4202         save_cast_details (cfg, klass, obj_reg, FALSE, NULL);
4203
4204         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
4205 #ifndef DISABLE_REMOTING
4206                 NEW_BBLOCK (cfg, interface_fail_bb);
4207         
4208                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4209                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
4210                 MONO_START_BB (cfg, interface_fail_bb);
4211                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4212
4213                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
4214
4215                 tmp_reg = alloc_preg (cfg);             
4216                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4217                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4218                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
4219                 
4220                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4221                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4222 #else
4223                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4224                 mini_emit_iface_cast (cfg, tmp_reg, klass, NULL, NULL);
4225                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, ok_result_bb);
4226 #endif
4227         } else {
4228 #ifndef DISABLE_REMOTING
4229                 NEW_BBLOCK (cfg, no_proxy_bb);
4230
4231                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
4232                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
4233                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
4234
4235                 tmp_reg = alloc_preg (cfg);
4236                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
4237                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
4238
4239                 tmp_reg = alloc_preg (cfg);
4240                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
4241                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
4242                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
4243
4244                 NEW_BBLOCK (cfg, fail_1_bb);
4245                 
4246                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
4247
4248                 MONO_START_BB (cfg, fail_1_bb);
4249
4250                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
4251                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4252
4253                 MONO_START_BB (cfg, no_proxy_bb);
4254
4255                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
4256 #else
4257                 g_error ("Transparent proxy support is disabled while trying to JIT code that uses it");
4258 #endif
4259         }
4260
4261         MONO_START_BB (cfg, ok_result_bb);
4262
4263         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4264
4265 #ifndef DISABLE_REMOTING
4266         MONO_START_BB (cfg, end_bb);
4267 #endif
4268
4269         /* FIXME: */
4270         MONO_INST_NEW (cfg, ins, OP_ICONST);
4271         ins->dreg = dreg;
4272         ins->type = STACK_I4;
4273
4274         return ins;
4275 }
4276
4277 /*
4278  * Returns NULL and set the cfg exception on error.
4279  */
4280 static G_GNUC_UNUSED MonoInst*
4281 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
4282 {
4283         MonoInst *ptr;
4284         int dreg;
4285         gpointer *trampoline;
4286         MonoInst *obj, *method_ins, *tramp_ins;
4287         MonoDomain *domain;
4288         guint8 **code_slot;
4289
4290         obj = handle_alloc (cfg, klass, FALSE, 0);
4291         if (!obj)
4292                 return NULL;
4293
4294         /* Inline the contents of mono_delegate_ctor */
4295
4296         /* Set target field */
4297         /* Optimize away setting of NULL target */
4298         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
4299                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
4300                 if (cfg->gen_write_barriers) {
4301                         dreg = alloc_preg (cfg);
4302                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
4303                         emit_write_barrier (cfg, ptr, target);
4304                 }
4305         }
4306
4307         /* Set method field */
4308         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
4309         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
4310         if (cfg->gen_write_barriers) {
4311                 dreg = alloc_preg (cfg);
4312                 EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
4313                 emit_write_barrier (cfg, ptr, method_ins);
4314         }
4315         /* 
4316          * To avoid looking up the compiled code belonging to the target method
4317          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
4318          * store it, and we fill it after the method has been compiled.
4319          */
4320         if (!cfg->compile_aot && !method->dynamic && !(cfg->opt & MONO_OPT_SHARED)) {
4321                 MonoInst *code_slot_ins;
4322
4323                 if (context_used) {
4324                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
4325                 } else {
4326                         domain = mono_domain_get ();
4327                         mono_domain_lock (domain);
4328                         if (!domain_jit_info (domain)->method_code_hash)
4329                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
4330                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
4331                         if (!code_slot) {
4332                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
4333                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
4334                         }
4335                         mono_domain_unlock (domain);
4336
4337                         EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
4338                 }
4339                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
4340         }
4341
4342         /* Set invoke_impl field */
4343         if (cfg->compile_aot) {
4344                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, klass);
4345         } else {
4346                 trampoline = mono_create_delegate_trampoline (cfg->domain, klass);
4347                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
4348         }
4349         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
4350
4351         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
4352
4353         return obj;
4354 }
4355
4356 static MonoInst*
4357 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
4358 {
4359         MonoJitICallInfo *info;
4360
4361         /* Need to register the icall so it gets an icall wrapper */
4362         info = mono_get_array_new_va_icall (rank);
4363
4364         cfg->flags |= MONO_CFG_HAS_VARARGS;
4365
4366         /* mono_array_new_va () needs a vararg calling convention */
4367         cfg->disable_llvm = TRUE;
4368
4369         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
4370         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
4371 }
4372
4373 static void
4374 mono_emit_load_got_addr (MonoCompile *cfg)
4375 {
4376         MonoInst *getaddr, *dummy_use;
4377
4378         if (!cfg->got_var || cfg->got_var_allocated)
4379                 return;
4380
4381         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
4382         getaddr->cil_code = cfg->header->code;
4383         getaddr->dreg = cfg->got_var->dreg;
4384
4385         /* Add it to the start of the first bblock */
4386         if (cfg->bb_entry->code) {
4387                 getaddr->next = cfg->bb_entry->code;
4388                 cfg->bb_entry->code = getaddr;
4389         }
4390         else
4391                 MONO_ADD_INS (cfg->bb_entry, getaddr);
4392
4393         cfg->got_var_allocated = TRUE;
4394
4395         /* 
4396          * Add a dummy use to keep the got_var alive, since real uses might
4397          * only be generated by the back ends.
4398          * Add it to end_bblock, so the variable's lifetime covers the whole
4399          * method.
4400          * It would be better to make the usage of the got var explicit in all
4401          * cases when the backend needs it (i.e. calls, throw etc.), so this
4402          * wouldn't be needed.
4403          */
4404         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
4405         MONO_ADD_INS (cfg->bb_exit, dummy_use);
4406 }
4407
4408 static int inline_limit;
4409 static gboolean inline_limit_inited;
4410
4411 static gboolean
4412 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
4413 {
4414         MonoMethodHeaderSummary header;
4415         MonoVTable *vtable;
4416 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4417         MonoMethodSignature *sig = mono_method_signature (method);
4418         int i;
4419 #endif
4420
4421         if (cfg->generic_sharing_context)
4422                 return FALSE;
4423
4424         if (cfg->inline_depth > 10)
4425                 return FALSE;
4426
4427 #ifdef MONO_ARCH_HAVE_LMF_OPS
4428         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
4429                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
4430             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
4431                 return TRUE;
4432 #endif
4433
4434
4435         if (!mono_method_get_header_summary (method, &header))
4436                 return FALSE;
4437
4438         /*runtime, icall and pinvoke are checked by summary call*/
4439         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
4440             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
4441             (mono_class_is_marshalbyref (method->klass)) ||
4442             header.has_clauses)
4443                 return FALSE;
4444
4445         /* also consider num_locals? */
4446         /* Do the size check early to avoid creating vtables */
4447         if (!inline_limit_inited) {
4448                 if (g_getenv ("MONO_INLINELIMIT"))
4449                         inline_limit = atoi (g_getenv ("MONO_INLINELIMIT"));
4450                 else
4451                         inline_limit = INLINE_LENGTH_LIMIT;
4452                 inline_limit_inited = TRUE;
4453         }
4454         if (header.code_size >= inline_limit && !(method->iflags & METHOD_IMPL_ATTRIBUTE_AGGRESSIVE_INLINING))
4455                 return FALSE;
4456
4457         /*
4458          * if we can initialize the class of the method right away, we do,
4459          * otherwise we don't allow inlining if the class needs initialization,
4460          * since it would mean inserting a call to mono_runtime_class_init()
4461          * inside the inlined code
4462          */
4463         if (!(cfg->opt & MONO_OPT_SHARED)) {
4464                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
4465                         if (cfg->run_cctors && method->klass->has_cctor) {
4466                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
4467                                 if (!method->klass->runtime_info)
4468                                         /* No vtable created yet */
4469                                         return FALSE;
4470                                 vtable = mono_class_vtable (cfg->domain, method->klass);
4471                                 if (!vtable)
4472                                         return FALSE;
4473                                 /* This makes so that inline cannot trigger */
4474                                 /* .cctors: too many apps depend on them */
4475                                 /* running with a specific order... */
4476                                 if (! vtable->initialized)
4477                                         return FALSE;
4478                                 mono_runtime_class_init (vtable);
4479                         }
4480                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
4481                         if (!method->klass->runtime_info)
4482                                 /* No vtable created yet */
4483                                 return FALSE;
4484                         vtable = mono_class_vtable (cfg->domain, method->klass);
4485                         if (!vtable)
4486                                 return FALSE;
4487                         if (!vtable->initialized)
4488                                 return FALSE;
4489                 }
4490         } else {
4491                 /* 
4492                  * If we're compiling for shared code
4493                  * the cctor will need to be run at aot method load time, for example,
4494                  * or at the end of the compilation of the inlining method.
4495                  */
4496                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
4497                         return FALSE;
4498         }
4499
4500         /*
4501          * CAS - do not inline methods with declarative security
4502          * Note: this has to be before any possible return TRUE;
4503          */
4504         if (mono_security_method_has_declsec (method))
4505                 return FALSE;
4506
4507 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
4508         if (mono_arch_is_soft_float ()) {
4509                 /* FIXME: */
4510                 if (sig->ret && sig->ret->type == MONO_TYPE_R4)
4511                         return FALSE;
4512                 for (i = 0; i < sig->param_count; ++i)
4513                         if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
4514                                 return FALSE;
4515         }
4516 #endif
4517
4518         return TRUE;
4519 }
4520
4521 static gboolean
4522 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoClass *klass, MonoVTable *vtable)
4523 {
4524         if (!cfg->compile_aot) {
4525                 g_assert (vtable);
4526                 if (vtable->initialized)
4527                         return FALSE;
4528         }
4529
4530         if (klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
4531                 return FALSE;
4532
4533         if (!mono_class_needs_cctor_run (klass, method))
4534                 return FALSE;
4535
4536         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (klass == method->klass))
4537                 /* The initialization is already done before the method is called */
4538                 return FALSE;
4539
4540         return TRUE;
4541 }
4542
4543 static MonoInst*
4544 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4545 {
4546         MonoInst *ins;
4547         guint32 size;
4548         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4549         int context_used;
4550
4551         if (mini_is_gsharedvt_klass (cfg, klass)) {
4552                 size = -1;
4553         } else {
4554                 mono_class_init (klass);
4555                 size = mono_class_array_element_size (klass);
4556         }
4557
4558         mult_reg = alloc_preg (cfg);
4559         array_reg = arr->dreg;
4560         index_reg = index->dreg;
4561
4562 #if SIZEOF_REGISTER == 8
4563         /* The array reg is 64 bits but the index reg is only 32 */
4564         if (COMPILE_LLVM (cfg)) {
4565                 /* Not needed */
4566                 index2_reg = index_reg;
4567         } else {
4568                 index2_reg = alloc_preg (cfg);
4569                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4570         }
4571 #else
4572         if (index->type == STACK_I8) {
4573                 index2_reg = alloc_preg (cfg);
4574                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4575         } else {
4576                 index2_reg = index_reg;
4577         }
4578 #endif
4579
4580         if (bcheck)
4581                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4582
4583 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4584         if (size == 1 || size == 2 || size == 4 || size == 8) {
4585                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4586
4587                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
4588                 ins->klass = mono_class_get_element_class (klass);
4589                 ins->type = STACK_MP;
4590
4591                 return ins;
4592         }
4593 #endif          
4594
4595         add_reg = alloc_ireg_mp (cfg);
4596
4597         if (size == -1) {
4598                 MonoInst *rgctx_ins;
4599
4600                 /* gsharedvt */
4601                 g_assert (cfg->generic_sharing_context);
4602                 context_used = mini_class_check_context_used (cfg, klass);
4603                 g_assert (context_used);
4604                 rgctx_ins = emit_get_gsharedvt_info (cfg, &klass->byval_arg, MONO_RGCTX_INFO_ARRAY_ELEMENT_SIZE);
4605                 MONO_EMIT_NEW_BIALU (cfg, OP_IMUL, mult_reg, index2_reg, rgctx_ins->dreg);
4606         } else {
4607                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4608         }
4609         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4610         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4611         ins->klass = mono_class_get_element_class (klass);
4612         ins->type = STACK_MP;
4613         MONO_ADD_INS (cfg->cbb, ins);
4614
4615         return ins;
4616 }
4617
4618 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4619 static MonoInst*
4620 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4621 {
4622         int bounds_reg = alloc_preg (cfg);
4623         int add_reg = alloc_ireg_mp (cfg);
4624         int mult_reg = alloc_preg (cfg);
4625         int mult2_reg = alloc_preg (cfg);
4626         int low1_reg = alloc_preg (cfg);
4627         int low2_reg = alloc_preg (cfg);
4628         int high1_reg = alloc_preg (cfg);
4629         int high2_reg = alloc_preg (cfg);
4630         int realidx1_reg = alloc_preg (cfg);
4631         int realidx2_reg = alloc_preg (cfg);
4632         int sum_reg = alloc_preg (cfg);
4633         int index1, index2, tmpreg;
4634         MonoInst *ins;
4635         guint32 size;
4636
4637         mono_class_init (klass);
4638         size = mono_class_array_element_size (klass);
4639
4640         index1 = index_ins1->dreg;
4641         index2 = index_ins2->dreg;
4642
4643 #if SIZEOF_REGISTER == 8
4644         /* The array reg is 64 bits but the index reg is only 32 */
4645         if (COMPILE_LLVM (cfg)) {
4646                 /* Not needed */
4647         } else {
4648                 tmpreg = alloc_preg (cfg);
4649                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index1);
4650                 index1 = tmpreg;
4651                 tmpreg = alloc_preg (cfg);
4652                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, tmpreg, index2);
4653                 index2 = tmpreg;
4654         }
4655 #else
4656         // FIXME: Do we need to do something here for i8 indexes, like in ldelema_1_ins ?
4657         tmpreg = -1;
4658 #endif
4659
4660         /* range checking */
4661         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4662                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4663
4664         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4665                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4666         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4667         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4668                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4669         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4670         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4671
4672         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4673                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4674         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4675         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4676                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
4677         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4678         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4679
4680         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4681         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4682         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4683         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4684         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4685
4686         ins->type = STACK_MP;
4687         ins->klass = klass;
4688         MONO_ADD_INS (cfg->cbb, ins);
4689
4690         return ins;
4691 }
4692 #endif
4693
4694 static MonoInst*
4695 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4696 {
4697         int rank;
4698         MonoInst *addr;
4699         MonoMethod *addr_method;
4700         int element_size;
4701
4702         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4703
4704         if (rank == 1)
4705                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
4706
4707 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4708         /* emit_ldelema_2 depends on OP_LMUL */
4709         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
4710                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
4711         }
4712 #endif
4713
4714         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4715         addr_method = mono_marshal_get_array_address (rank, element_size);
4716         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4717
4718         return addr;
4719 }
4720
4721 static MonoBreakPolicy
4722 always_insert_breakpoint (MonoMethod *method)
4723 {
4724         return MONO_BREAK_POLICY_ALWAYS;
4725 }
4726
4727 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4728
4729 /**
4730  * mono_set_break_policy:
4731  * policy_callback: the new callback function
4732  *
4733  * Allow embedders to decide wherther to actually obey breakpoint instructions
4734  * (both break IL instructions and Debugger.Break () method calls), for example
4735  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4736  * untrusted or semi-trusted code.
4737  *
4738  * @policy_callback will be called every time a break point instruction needs to
4739  * be inserted with the method argument being the method that calls Debugger.Break()
4740  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4741  * if it wants the breakpoint to not be effective in the given method.
4742  * #MONO_BREAK_POLICY_ALWAYS is the default.
4743  */
4744 void
4745 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4746 {
4747         if (policy_callback)
4748                 break_policy_func = policy_callback;
4749         else
4750                 break_policy_func = always_insert_breakpoint;
4751 }
4752
4753 static gboolean
4754 should_insert_brekpoint (MonoMethod *method) {
4755         switch (break_policy_func (method)) {
4756         case MONO_BREAK_POLICY_ALWAYS:
4757                 return TRUE;
4758         case MONO_BREAK_POLICY_NEVER:
4759                 return FALSE;
4760         case MONO_BREAK_POLICY_ON_DBG:
4761                 return mono_debug_using_mono_debugger ();
4762         default:
4763                 g_warning ("Incorrect value returned from break policy callback");
4764                 return FALSE;
4765         }
4766 }
4767
4768 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4769 static MonoInst*
4770 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4771 {
4772         MonoInst *addr, *store, *load;
4773         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4774
4775         /* the bounds check is already done by the callers */
4776         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4777         if (is_set) {
4778                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4779                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4780                 if (mini_type_is_reference (cfg, fsig->params [2]))
4781                         emit_write_barrier (cfg, addr, load);
4782         } else {
4783                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4784                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4785         }
4786         return store;
4787 }
4788
4789
4790 static gboolean
4791 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
4792 {
4793         return mini_type_is_reference (cfg, &klass->byval_arg);
4794 }
4795
4796 static MonoInst*
4797 emit_array_store (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, gboolean safety_checks)
4798 {
4799         if (safety_checks && generic_class_is_reference_type (cfg, klass) &&
4800                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
4801                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
4802                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
4803                 MonoInst *iargs [3];
4804
4805                 if (!helper->slot)
4806                         mono_class_setup_vtable (obj_array);
4807                 g_assert (helper->slot);
4808
4809                 if (sp [0]->type != STACK_OBJ)
4810                         return NULL;
4811                 if (sp [2]->type != STACK_OBJ)
4812                         return NULL;
4813
4814                 iargs [2] = sp [2];
4815                 iargs [1] = sp [1];
4816                 iargs [0] = sp [0];
4817
4818                 return mono_emit_method_call (cfg, helper, iargs, sp [0]);
4819         } else {
4820                 MonoInst *ins;
4821
4822                 if (mini_is_gsharedvt_klass (cfg, klass)) {
4823                         MonoInst *addr;
4824
4825                         // FIXME-VT: OP_ICONST optimization
4826                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
4827                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4828                         ins->opcode = OP_STOREV_MEMBASE;
4829                 } else if (sp [1]->opcode == OP_ICONST) {
4830                         int array_reg = sp [0]->dreg;
4831                         int index_reg = sp [1]->dreg;
4832                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
4833
4834                         if (safety_checks)
4835                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
4836                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
4837                 } else {
4838                         MonoInst *addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], safety_checks);
4839                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
4840                         if (generic_class_is_reference_type (cfg, klass))
4841                                 emit_write_barrier (cfg, addr, sp [2]);
4842                 }
4843                 return ins;
4844         }
4845 }
4846
4847 static MonoInst*
4848 emit_array_unsafe_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4849 {
4850         MonoClass *eklass;
4851         
4852         if (is_set)
4853                 eklass = mono_class_from_mono_type (fsig->params [2]);
4854         else
4855                 eklass = mono_class_from_mono_type (fsig->ret);
4856
4857
4858         if (is_set) {
4859                 return emit_array_store (cfg, eklass, args, FALSE);
4860         } else {
4861                 MonoInst *ins, *addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4862                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &eklass->byval_arg, addr->dreg, 0);
4863                 return ins;
4864         }
4865 }
4866
4867 static MonoInst*
4868 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4869 {
4870         MonoInst *ins = NULL;
4871 #ifdef MONO_ARCH_SIMD_INTRINSICS
4872         if (cfg->opt & MONO_OPT_SIMD) {
4873                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
4874                 if (ins)
4875                         return ins;
4876         }
4877 #endif
4878
4879         return ins;
4880 }
4881
4882 static MonoInst*
4883 emit_memory_barrier (MonoCompile *cfg, int kind)
4884 {
4885         MonoInst *ins = NULL;
4886         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4887         MONO_ADD_INS (cfg->cbb, ins);
4888         ins->backend.memory_barrier_kind = kind;
4889
4890         return ins;
4891 }
4892
4893 static MonoInst*
4894 llvm_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4895 {
4896         MonoInst *ins = NULL;
4897         int opcode = 0;
4898
4899         /* The LLVM backend supports these intrinsics */
4900         if (cmethod->klass == mono_defaults.math_class) {
4901                 if (strcmp (cmethod->name, "Sin") == 0) {
4902                         opcode = OP_SIN;
4903                 } else if (strcmp (cmethod->name, "Cos") == 0) {
4904                         opcode = OP_COS;
4905                 } else if (strcmp (cmethod->name, "Sqrt") == 0) {
4906                         opcode = OP_SQRT;
4907                 } else if (strcmp (cmethod->name, "Abs") == 0 && fsig->params [0]->type == MONO_TYPE_R8) {
4908                         opcode = OP_ABS;
4909                 }
4910
4911                 if (opcode) {
4912                         MONO_INST_NEW (cfg, ins, opcode);
4913                         ins->type = STACK_R8;
4914                         ins->dreg = mono_alloc_freg (cfg);
4915                         ins->sreg1 = args [0]->dreg;
4916                         MONO_ADD_INS (cfg->cbb, ins);
4917                 }
4918
4919                 opcode = 0;
4920                 if (cfg->opt & MONO_OPT_CMOV) {
4921                         if (strcmp (cmethod->name, "Min") == 0) {
4922                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4923                                         opcode = OP_IMIN;
4924                                 if (fsig->params [0]->type == MONO_TYPE_U4)
4925                                         opcode = OP_IMIN_UN;
4926                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
4927                                         opcode = OP_LMIN;
4928                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
4929                                         opcode = OP_LMIN_UN;
4930                         } else if (strcmp (cmethod->name, "Max") == 0) {
4931                                 if (fsig->params [0]->type == MONO_TYPE_I4)
4932                                         opcode = OP_IMAX;
4933                                 if (fsig->params [0]->type == MONO_TYPE_U4)
4934                                         opcode = OP_IMAX_UN;
4935                                 else if (fsig->params [0]->type == MONO_TYPE_I8)
4936                                         opcode = OP_LMAX;
4937                                 else if (fsig->params [0]->type == MONO_TYPE_U8)
4938                                         opcode = OP_LMAX_UN;
4939                         }
4940                 }
4941
4942                 if (opcode) {
4943                         MONO_INST_NEW (cfg, ins, opcode);
4944                         ins->type = fsig->params [0]->type == MONO_TYPE_I4 ? STACK_I4 : STACK_I8;
4945                         ins->dreg = mono_alloc_ireg (cfg);
4946                         ins->sreg1 = args [0]->dreg;
4947                         ins->sreg2 = args [1]->dreg;
4948                         MONO_ADD_INS (cfg->cbb, ins);
4949                 }
4950         }
4951
4952         return ins;
4953 }
4954
4955 static MonoInst*
4956 mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4957 {
4958         if (cmethod->klass == mono_defaults.array_class) {
4959                 if (strcmp (cmethod->name, "UnsafeStore") == 0)
4960                         return emit_array_unsafe_access (cfg, fsig, args, TRUE);
4961                 if (strcmp (cmethod->name, "UnsafeLoad") == 0)
4962                         return emit_array_unsafe_access (cfg, fsig, args, FALSE);
4963         }
4964
4965         return NULL;
4966 }
4967
4968 static MonoInst*
4969 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4970 {
4971         MonoInst *ins = NULL;
4972         
4973         static MonoClass *runtime_helpers_class = NULL;
4974         if (! runtime_helpers_class)
4975                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
4976                         "System.Runtime.CompilerServices", "RuntimeHelpers");
4977
4978         if (cmethod->klass == mono_defaults.string_class) {
4979                 if (strcmp (cmethod->name, "get_Chars") == 0) {
4980                         int dreg = alloc_ireg (cfg);
4981                         int index_reg = alloc_preg (cfg);
4982                         int mult_reg = alloc_preg (cfg);
4983                         int add_reg = alloc_preg (cfg);
4984
4985 #if SIZEOF_REGISTER == 8
4986                         /* The array reg is 64 bits but the index reg is only 32 */
4987                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
4988 #else
4989                         index_reg = args [1]->dreg;
4990 #endif  
4991                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
4992
4993 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4994                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
4995                         add_reg = ins->dreg;
4996                         /* Avoid a warning */
4997                         mult_reg = 0;
4998                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
4999                                                                    add_reg, 0);
5000 #else
5001                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
5002                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5003                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
5004                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
5005 #endif
5006                         type_from_op (ins, NULL, NULL);
5007                         return ins;
5008                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5009                         int dreg = alloc_ireg (cfg);
5010                         /* Decompose later to allow more optimizations */
5011                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
5012                         ins->type = STACK_I4;
5013                         ins->flags |= MONO_INST_FAULT;
5014                         cfg->cbb->has_array_access = TRUE;
5015                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
5016
5017                         return ins;
5018                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
5019                         int mult_reg = alloc_preg (cfg);
5020                         int add_reg = alloc_preg (cfg);
5021
5022                         /* The corlib functions check for oob already. */
5023                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
5024                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
5025                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
5026                         return cfg->cbb->last_ins;
5027                 } else 
5028                         return NULL;
5029         } else if (cmethod->klass == mono_defaults.object_class) {
5030
5031                 if (strcmp (cmethod->name, "GetType") == 0) {
5032                         int dreg = alloc_ireg_ref (cfg);
5033                         int vt_reg = alloc_preg (cfg);
5034                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5035                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
5036                         type_from_op (ins, NULL, NULL);
5037
5038                         return ins;
5039 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
5040                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
5041                         int dreg = alloc_ireg (cfg);
5042                         int t1 = alloc_ireg (cfg);
5043         
5044                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
5045                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
5046                         ins->type = STACK_I4;
5047
5048                         return ins;
5049 #endif
5050                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
5051                         MONO_INST_NEW (cfg, ins, OP_NOP);
5052                         MONO_ADD_INS (cfg->cbb, ins);
5053                         return ins;
5054                 } else
5055                         return NULL;
5056         } else if (cmethod->klass == mono_defaults.array_class) {
5057                 if (!cfg->gsharedvt && strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
5058                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
5059
5060 #ifndef MONO_BIG_ARRAYS
5061                 /*
5062                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
5063                  * Array methods.
5064                  */
5065                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
5066                         int dreg = alloc_ireg (cfg);
5067                         int bounds_reg = alloc_ireg_mp (cfg);
5068                         MonoBasicBlock *end_bb, *szarray_bb;
5069                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
5070
5071                         NEW_BBLOCK (cfg, end_bb);
5072                         NEW_BBLOCK (cfg, szarray_bb);
5073
5074                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
5075                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
5076                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
5077                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
5078                         /* Non-szarray case */
5079                         if (get_length)
5080                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5081                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
5082                         else
5083                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5084                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
5085                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
5086                         MONO_START_BB (cfg, szarray_bb);
5087                         /* Szarray case */
5088                         if (get_length)
5089                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
5090                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5091                         else
5092                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
5093                         MONO_START_BB (cfg, end_bb);
5094
5095                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
5096                         ins->type = STACK_I4;
5097                         
5098                         return ins;
5099                 }
5100 #endif
5101
5102                 if (cmethod->name [0] != 'g')
5103                         return NULL;
5104
5105                 if (strcmp (cmethod->name, "get_Rank") == 0) {
5106                         int dreg = alloc_ireg (cfg);
5107                         int vtable_reg = alloc_preg (cfg);
5108                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
5109                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
5110                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
5111                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
5112                         type_from_op (ins, NULL, NULL);
5113
5114                         return ins;
5115                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
5116                         int dreg = alloc_ireg (cfg);
5117
5118                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
5119                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
5120                         type_from_op (ins, NULL, NULL);
5121
5122                         return ins;
5123                 } else
5124                         return NULL;
5125         } else if (cmethod->klass == runtime_helpers_class) {
5126
5127                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
5128                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
5129                         return ins;
5130                 } else
5131                         return NULL;
5132         } else if (cmethod->klass == mono_defaults.thread_class) {
5133                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
5134                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
5135                         MONO_ADD_INS (cfg->cbb, ins);
5136                         return ins;
5137                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
5138                         return emit_memory_barrier (cfg, FullBarrier);
5139                 }
5140         } else if (cmethod->klass == mono_defaults.monitor_class) {
5141
5142                 /* FIXME this should be integrated to the check below once we support the trampoline version */
5143 #if defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5144                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) {
5145                         MonoMethod *fast_method = NULL;
5146
5147                         /* Avoid infinite recursion */
5148                         if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN && !strcmp (cfg->method->name, "FastMonitorEnterV4"))
5149                                 return NULL;
5150                                 
5151                         fast_method = mono_monitor_get_fast_path (cmethod);
5152                         if (!fast_method)
5153                                 return NULL;
5154
5155                         return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5156                 }
5157 #endif
5158
5159 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
5160                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
5161                         MonoCallInst *call;
5162
5163                         if (COMPILE_LLVM (cfg)) {
5164                                 /* 
5165                                  * Pass the argument normally, the LLVM backend will handle the
5166                                  * calling convention problems.
5167                                  */
5168                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5169                         } else {
5170                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
5171                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5172                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5173                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5174                         }
5175
5176                         return (MonoInst*)call;
5177                 } else if (strcmp (cmethod->name, "Exit") == 0) {
5178                         MonoCallInst *call;
5179
5180                         if (COMPILE_LLVM (cfg)) {
5181                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
5182                         } else {
5183                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
5184                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
5185                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
5186                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
5187                         }
5188
5189                         return (MonoInst*)call;
5190                 }
5191 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
5192                 {
5193                 MonoMethod *fast_method = NULL;
5194
5195                 /* Avoid infinite recursion */
5196                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
5197                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
5198                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
5199                         return NULL;
5200
5201                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 2) ||
5202                                 strcmp (cmethod->name, "Exit") == 0)
5203                         fast_method = mono_monitor_get_fast_path (cmethod);
5204                 if (!fast_method)
5205                         return NULL;
5206
5207                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
5208                 }
5209 #endif
5210         } else if (cmethod->klass->image == mono_defaults.corlib &&
5211                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
5212                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
5213                 ins = NULL;
5214
5215 #if SIZEOF_REGISTER == 8
5216                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
5217                         /* 64 bit reads are already atomic */
5218                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
5219                         ins->dreg = mono_alloc_preg (cfg);
5220                         ins->inst_basereg = args [0]->dreg;
5221                         ins->inst_offset = 0;
5222                         MONO_ADD_INS (cfg->cbb, ins);
5223                 }
5224 #endif
5225
5226 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
5227                 if (strcmp (cmethod->name, "Increment") == 0) {
5228                         MonoInst *ins_iconst;
5229                         guint32 opcode = 0;
5230
5231                         if (fsig->params [0]->type == MONO_TYPE_I4)
5232                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5233 #if SIZEOF_REGISTER == 8
5234                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5235                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5236 #endif
5237                         if (opcode) {
5238                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5239                                 ins_iconst->inst_c0 = 1;
5240                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5241                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5242
5243                                 MONO_INST_NEW (cfg, ins, opcode);
5244                                 ins->dreg = mono_alloc_ireg (cfg);
5245                                 ins->inst_basereg = args [0]->dreg;
5246                                 ins->inst_offset = 0;
5247                                 ins->sreg2 = ins_iconst->dreg;
5248                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5249                                 MONO_ADD_INS (cfg->cbb, ins);
5250                         }
5251                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
5252                         MonoInst *ins_iconst;
5253                         guint32 opcode = 0;
5254
5255                         if (fsig->params [0]->type == MONO_TYPE_I4)
5256                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5257 #if SIZEOF_REGISTER == 8
5258                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5259                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5260 #endif
5261                         if (opcode) {
5262                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
5263                                 ins_iconst->inst_c0 = -1;
5264                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
5265                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
5266
5267                                 MONO_INST_NEW (cfg, ins, opcode);
5268                                 ins->dreg = mono_alloc_ireg (cfg);
5269                                 ins->inst_basereg = args [0]->dreg;
5270                                 ins->inst_offset = 0;
5271                                 ins->sreg2 = ins_iconst->dreg;
5272                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5273                                 MONO_ADD_INS (cfg->cbb, ins);
5274                         }
5275                 } else if (strcmp (cmethod->name, "Add") == 0) {
5276                         guint32 opcode = 0;
5277
5278                         if (fsig->params [0]->type == MONO_TYPE_I4)
5279                                 opcode = OP_ATOMIC_ADD_NEW_I4;
5280 #if SIZEOF_REGISTER == 8
5281                         else if (fsig->params [0]->type == MONO_TYPE_I8)
5282                                 opcode = OP_ATOMIC_ADD_NEW_I8;
5283 #endif
5284
5285                         if (opcode) {
5286                                 MONO_INST_NEW (cfg, ins, opcode);
5287                                 ins->dreg = mono_alloc_ireg (cfg);
5288                                 ins->inst_basereg = args [0]->dreg;
5289                                 ins->inst_offset = 0;
5290                                 ins->sreg2 = args [1]->dreg;
5291                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
5292                                 MONO_ADD_INS (cfg->cbb, ins);
5293                         }
5294                 }
5295 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
5296
5297 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
5298                 if (strcmp (cmethod->name, "Exchange") == 0) {
5299                         guint32 opcode;
5300                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
5301
5302                         if (fsig->params [0]->type == MONO_TYPE_I4)
5303                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5304 #if SIZEOF_REGISTER == 8
5305                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
5306                                         (fsig->params [0]->type == MONO_TYPE_I))
5307                                 opcode = OP_ATOMIC_EXCHANGE_I8;
5308 #else
5309                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I))
5310                                 opcode = OP_ATOMIC_EXCHANGE_I4;
5311 #endif
5312                         else
5313                                 return NULL;
5314
5315                         MONO_INST_NEW (cfg, ins, opcode);
5316                         ins->dreg = is_ref ? mono_alloc_ireg_ref (cfg) : mono_alloc_ireg (cfg);
5317                         ins->inst_basereg = args [0]->dreg;
5318                         ins->inst_offset = 0;
5319                         ins->sreg2 = args [1]->dreg;
5320                         MONO_ADD_INS (cfg->cbb, ins);
5321
5322                         switch (fsig->params [0]->type) {
5323                         case MONO_TYPE_I4:
5324                                 ins->type = STACK_I4;
5325                                 break;
5326                         case MONO_TYPE_I8:
5327                         case MONO_TYPE_I:
5328                                 ins->type = STACK_I8;
5329                                 break;
5330                         case MONO_TYPE_OBJECT:
5331                                 ins->type = STACK_OBJ;
5332                                 break;
5333                         default:
5334                                 g_assert_not_reached ();
5335                         }
5336
5337                         if (cfg->gen_write_barriers && is_ref)
5338                                 emit_write_barrier (cfg, args [0], args [1]);
5339                 }
5340 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
5341  
5342 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
5343                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
5344                         int size = 0;
5345                         gboolean is_ref = mini_type_is_reference (cfg, fsig->params [1]);
5346                         if (fsig->params [1]->type == MONO_TYPE_I4)
5347                                 size = 4;
5348                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
5349                                 size = sizeof (gpointer);
5350                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
5351                                 size = 8;
5352                         if (size == 4) {
5353                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
5354                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5355                                 ins->sreg1 = args [0]->dreg;
5356                                 ins->sreg2 = args [1]->dreg;
5357                                 ins->sreg3 = args [2]->dreg;
5358                                 ins->type = STACK_I4;
5359                                 MONO_ADD_INS (cfg->cbb, ins);
5360                         } else if (size == 8) {
5361                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
5362                                 ins->dreg = is_ref ? alloc_ireg_ref (cfg) : alloc_ireg (cfg);
5363                                 ins->sreg1 = args [0]->dreg;
5364                                 ins->sreg2 = args [1]->dreg;
5365                                 ins->sreg3 = args [2]->dreg;
5366                                 ins->type = STACK_I8;
5367                                 MONO_ADD_INS (cfg->cbb, ins);
5368                         } else {
5369                                 /* g_assert_not_reached (); */
5370                         }
5371                         if (cfg->gen_write_barriers && is_ref)
5372                                 emit_write_barrier (cfg, args [0], args [1]);
5373                 }
5374 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
5375
5376                 if (strcmp (cmethod->name, "MemoryBarrier") == 0)
5377                         ins = emit_memory_barrier (cfg, FullBarrier);
5378
5379                 if (ins)
5380                         return ins;
5381         } else if (cmethod->klass->image == mono_defaults.corlib) {
5382                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
5383                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
5384                         if (should_insert_brekpoint (cfg->method)) {
5385                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
5386                         } else {
5387                                 MONO_INST_NEW (cfg, ins, OP_NOP);
5388                                 MONO_ADD_INS (cfg->cbb, ins);
5389                         }
5390                         return ins;
5391                 }
5392                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
5393                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
5394 #ifdef TARGET_WIN32
5395                         EMIT_NEW_ICONST (cfg, ins, 1);
5396 #else
5397                         EMIT_NEW_ICONST (cfg, ins, 0);
5398 #endif
5399                         return ins;
5400                 }
5401         } else if (cmethod->klass == mono_defaults.math_class) {
5402                 /* 
5403                  * There is general branches code for Min/Max, but it does not work for 
5404                  * all inputs:
5405                  * http://everything2.com/?node_id=1051618
5406                  */
5407         } else if ((!strcmp (cmethod->klass->image->assembly->aname.name, "MonoMac") || !strcmp (cmethod->klass->image->assembly->aname.name, "monotouch")) && !strcmp (cmethod->klass->name, "Selector") && !strcmp (cmethod->name, "GetHandle") && cfg->compile_aot && (args [0]->opcode == OP_GOT_ENTRY || args[0]->opcode == OP_AOTCONST)) {
5408 #ifdef MONO_ARCH_HAVE_OBJC_GET_SELECTOR
5409                 MonoInst *pi;
5410                 MonoJumpInfoToken *ji;
5411                 MonoString *s;
5412
5413                 cfg->disable_llvm = TRUE;
5414
5415                 if (args [0]->opcode == OP_GOT_ENTRY) {
5416                         pi = args [0]->inst_p1;
5417                         g_assert (pi->opcode == OP_PATCH_INFO);
5418                         g_assert ((int)pi->inst_p1 == MONO_PATCH_INFO_LDSTR);
5419                         ji = pi->inst_p0;
5420                 } else {
5421                         g_assert ((int)args [0]->inst_p1 == MONO_PATCH_INFO_LDSTR);
5422                         ji = args [0]->inst_p0;
5423                 }
5424
5425                 NULLIFY_INS (args [0]);
5426
5427                 // FIXME: Ugly
5428                 s = mono_ldstr (cfg->domain, ji->image, mono_metadata_token_index (ji->token));
5429                 MONO_INST_NEW (cfg, ins, OP_OBJC_GET_SELECTOR);
5430                 ins->dreg = mono_alloc_ireg (cfg);
5431                 // FIXME: Leaks
5432                 ins->inst_p0 = mono_string_to_utf8 (s);
5433                 MONO_ADD_INS (cfg->cbb, ins);
5434                 return ins;
5435 #endif
5436         }
5437
5438 #ifdef MONO_ARCH_SIMD_INTRINSICS
5439         if (cfg->opt & MONO_OPT_SIMD) {
5440                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
5441                 if (ins)
5442                         return ins;
5443         }
5444 #endif
5445
5446         if (COMPILE_LLVM (cfg)) {
5447                 ins = llvm_emit_inst_for_method (cfg, cmethod, fsig, args);
5448                 if (ins)
5449                         return ins;
5450         }
5451
5452         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
5453 }
5454
5455 /*
5456  * This entry point could be used later for arbitrary method
5457  * redirection.
5458  */
5459 inline static MonoInst*
5460 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
5461                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
5462 {
5463         if (method->klass == mono_defaults.string_class) {
5464                 /* managed string allocation support */
5465                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
5466                         MonoInst *iargs [2];
5467                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
5468                         MonoMethod *managed_alloc = NULL;
5469
5470                         g_assert (vtable); /*Should not fail since it System.String*/
5471 #ifndef MONO_CROSS_COMPILE
5472                         managed_alloc = mono_gc_get_managed_allocator (method->klass, FALSE);
5473 #endif
5474                         if (!managed_alloc)
5475                                 return NULL;
5476                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
5477                         iargs [1] = args [0];
5478                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
5479                 }
5480         }
5481         return NULL;
5482 }
5483
5484 static void
5485 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
5486 {
5487         MonoInst *store, *temp;
5488         int i;
5489
5490         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
5491                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
5492
5493                 /*
5494                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
5495                  * would be different than the MonoInst's used to represent arguments, and
5496                  * the ldelema implementation can't deal with that.
5497                  * Solution: When ldelema is used on an inline argument, create a var for 
5498                  * it, emit ldelema on that var, and emit the saving code below in
5499                  * inline_method () if needed.
5500                  */
5501                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
5502                 cfg->args [i] = temp;
5503                 /* This uses cfg->args [i] which is set by the preceeding line */
5504                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
5505                 store->cil_code = sp [0]->cil_code;
5506                 sp++;
5507         }
5508 }
5509
5510 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
5511 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
5512
5513 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5514 static gboolean
5515 check_inline_called_method_name_limit (MonoMethod *called_method)
5516 {
5517         int strncmp_result;
5518         static const char *limit = NULL;
5519         
5520         if (limit == NULL) {
5521                 const char *limit_string = g_getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
5522
5523                 if (limit_string != NULL)
5524                         limit = limit_string;
5525                 else
5526                         limit = "";
5527         }
5528
5529         if (limit [0] != '\0') {
5530                 char *called_method_name = mono_method_full_name (called_method, TRUE);
5531
5532                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
5533                 g_free (called_method_name);
5534         
5535                 //return (strncmp_result <= 0);
5536                 return (strncmp_result == 0);
5537         } else {
5538                 return TRUE;
5539         }
5540 }
5541 #endif
5542
5543 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5544 static gboolean
5545 check_inline_caller_method_name_limit (MonoMethod *caller_method)
5546 {
5547         int strncmp_result;
5548         static const char *limit = NULL;
5549         
5550         if (limit == NULL) {
5551                 const char *limit_string = g_getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
5552                 if (limit_string != NULL) {
5553                         limit = limit_string;
5554                 } else {
5555                         limit = "";
5556                 }
5557         }
5558
5559         if (limit [0] != '\0') {
5560                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
5561
5562                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
5563                 g_free (caller_method_name);
5564         
5565                 //return (strncmp_result <= 0);
5566                 return (strncmp_result == 0);
5567         } else {
5568                 return TRUE;
5569         }
5570 }
5571 #endif
5572
5573 static void
5574 emit_init_rvar (MonoCompile *cfg, MonoInst *rvar, MonoType *rtype)
5575 {
5576         static double r8_0 = 0.0;
5577         MonoInst *ins;
5578
5579         switch (rvar->type) {
5580         case STACK_I4:
5581                 MONO_EMIT_NEW_ICONST (cfg, rvar->dreg, 0);
5582                 break;
5583         case STACK_I8:
5584                 MONO_EMIT_NEW_I8CONST (cfg, rvar->dreg, 0);
5585                 break;
5586         case STACK_PTR:
5587         case STACK_MP:
5588         case STACK_OBJ:
5589                 MONO_EMIT_NEW_PCONST (cfg, rvar->dreg, 0);
5590                 break;
5591         case STACK_R8:
5592                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
5593                 ins->type = STACK_R8;
5594                 ins->inst_p0 = (void*)&r8_0;
5595                 ins->dreg = rvar->dreg;
5596                 MONO_ADD_INS (cfg->cbb, ins);
5597                 break;
5598         case STACK_VTYPE:
5599                 MONO_EMIT_NEW_VZERO (cfg, rvar->dreg, mono_class_from_mono_type (rtype));
5600                 break;
5601         default:
5602                 g_assert_not_reached ();
5603         }
5604 }
5605
5606 static int
5607 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
5608                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
5609 {
5610         MonoInst *ins, *rvar = NULL;
5611         MonoMethodHeader *cheader;
5612         MonoBasicBlock *ebblock, *sbblock;
5613         int i, costs;
5614         MonoMethod *prev_inlined_method;
5615         MonoInst **prev_locals, **prev_args;
5616         MonoType **prev_arg_types;
5617         guint prev_real_offset;
5618         GHashTable *prev_cbb_hash;
5619         MonoBasicBlock **prev_cil_offset_to_bb;
5620         MonoBasicBlock *prev_cbb;
5621         unsigned char* prev_cil_start;
5622         guint32 prev_cil_offset_to_bb_len;
5623         MonoMethod *prev_current_method;
5624         MonoGenericContext *prev_generic_context;
5625         gboolean ret_var_set, prev_ret_var_set, virtual = FALSE;
5626
5627         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
5628
5629 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
5630         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
5631                 return 0;
5632 #endif
5633 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
5634         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
5635                 return 0;
5636 #endif
5637
5638         if (cfg->verbose_level > 2)
5639                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5640
5641         if (!cmethod->inline_info) {
5642                 cfg->stat_inlineable_methods++;
5643                 cmethod->inline_info = 1;
5644         }
5645
5646         /* allocate local variables */
5647         cheader = mono_method_get_header (cmethod);
5648
5649         if (cheader == NULL || mono_loader_get_last_error ()) {
5650                 MonoLoaderError *error = mono_loader_get_last_error ();
5651
5652                 if (cheader)
5653                         mono_metadata_free_mh (cheader);
5654                 if (inline_always && error)
5655                         mono_cfg_set_exception (cfg, error->exception_type);
5656
5657                 mono_loader_clear_error ();
5658                 return 0;
5659         }
5660
5661         /*Must verify before creating locals as it can cause the JIT to assert.*/
5662         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
5663                 mono_metadata_free_mh (cheader);
5664                 return 0;
5665         }
5666
5667         /* allocate space to store the return value */
5668         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
5669                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
5670         }
5671
5672         prev_locals = cfg->locals;
5673         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
5674         for (i = 0; i < cheader->num_locals; ++i)
5675                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
5676
5677         /* allocate start and end blocks */
5678         /* This is needed so if the inline is aborted, we can clean up */
5679         NEW_BBLOCK (cfg, sbblock);
5680         sbblock->real_offset = real_offset;
5681
5682         NEW_BBLOCK (cfg, ebblock);
5683         ebblock->block_num = cfg->num_bblocks++;
5684         ebblock->real_offset = real_offset;
5685
5686         prev_args = cfg->args;
5687         prev_arg_types = cfg->arg_types;
5688         prev_inlined_method = cfg->inlined_method;
5689         cfg->inlined_method = cmethod;
5690         cfg->ret_var_set = FALSE;
5691         cfg->inline_depth ++;
5692         prev_real_offset = cfg->real_offset;
5693         prev_cbb_hash = cfg->cbb_hash;
5694         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
5695         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
5696         prev_cil_start = cfg->cil_start;
5697         prev_cbb = cfg->cbb;
5698         prev_current_method = cfg->current_method;
5699         prev_generic_context = cfg->generic_context;
5700         prev_ret_var_set = cfg->ret_var_set;
5701
5702         if (*ip == CEE_CALLVIRT && !(cmethod->flags & METHOD_ATTRIBUTE_STATIC))
5703                 virtual = TRUE;
5704
5705         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, virtual);
5706
5707         ret_var_set = cfg->ret_var_set;
5708
5709         cfg->inlined_method = prev_inlined_method;
5710         cfg->real_offset = prev_real_offset;
5711         cfg->cbb_hash = prev_cbb_hash;
5712         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
5713         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
5714         cfg->cil_start = prev_cil_start;
5715         cfg->locals = prev_locals;
5716         cfg->args = prev_args;
5717         cfg->arg_types = prev_arg_types;
5718         cfg->current_method = prev_current_method;
5719         cfg->generic_context = prev_generic_context;
5720         cfg->ret_var_set = prev_ret_var_set;
5721         cfg->inline_depth --;
5722
5723         if ((costs >= 0 && costs < 60) || inline_always) {
5724                 if (cfg->verbose_level > 2)
5725                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
5726                 
5727                 cfg->stat_inlined_methods++;
5728
5729                 /* always add some code to avoid block split failures */
5730                 MONO_INST_NEW (cfg, ins, OP_NOP);
5731                 MONO_ADD_INS (prev_cbb, ins);
5732
5733                 prev_cbb->next_bb = sbblock;
5734                 link_bblock (cfg, prev_cbb, sbblock);
5735
5736                 /* 
5737                  * Get rid of the begin and end bblocks if possible to aid local
5738                  * optimizations.
5739                  */
5740                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
5741
5742                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
5743                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
5744
5745                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
5746                         MonoBasicBlock *prev = ebblock->in_bb [0];
5747                         mono_merge_basic_blocks (cfg, prev, ebblock);
5748                         cfg->cbb = prev;
5749                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
5750                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
5751                                 cfg->cbb = prev_cbb;
5752                         }
5753                 } else {
5754                         /* 
5755                          * Its possible that the rvar is set in some prev bblock, but not in others.
5756                          * (#1835).
5757                          */
5758                         if (rvar) {
5759                                 MonoBasicBlock *bb;
5760
5761                                 for (i = 0; i < ebblock->in_count; ++i) {
5762                                         bb = ebblock->in_bb [i];
5763
5764                                         if (bb->last_ins && bb->last_ins->opcode == OP_NOT_REACHED) {
5765                                                 cfg->cbb = bb;
5766
5767                                                 emit_init_rvar (cfg, rvar, fsig->ret);
5768                                         }
5769                                 }
5770                         }
5771
5772                         cfg->cbb = ebblock;
5773                 }
5774
5775                 if (rvar) {
5776                         /*
5777                          * If the inlined method contains only a throw, then the ret var is not 
5778                          * set, so set it to a dummy value.
5779                          */
5780                         if (!ret_var_set)
5781                                 emit_init_rvar (cfg, rvar, fsig->ret);
5782
5783                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
5784                         *sp++ = ins;
5785                 }
5786                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
5787                 return costs + 1;
5788         } else {
5789                 if (cfg->verbose_level > 2)
5790                         printf ("INLINE ABORTED %s (cost %d)\n", mono_method_full_name (cmethod, TRUE), costs);
5791                 cfg->exception_type = MONO_EXCEPTION_NONE;
5792                 mono_loader_clear_error ();
5793
5794                 /* This gets rid of the newly added bblocks */
5795                 cfg->cbb = prev_cbb;
5796         }
5797         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
5798         return 0;
5799 }
5800
5801 /*
5802  * Some of these comments may well be out-of-date.
5803  * Design decisions: we do a single pass over the IL code (and we do bblock 
5804  * splitting/merging in the few cases when it's required: a back jump to an IL
5805  * address that was not already seen as bblock starting point).
5806  * Code is validated as we go (full verification is still better left to metadata/verify.c).
5807  * Complex operations are decomposed in simpler ones right away. We need to let the 
5808  * arch-specific code peek and poke inside this process somehow (except when the 
5809  * optimizations can take advantage of the full semantic info of coarse opcodes).
5810  * All the opcodes of the form opcode.s are 'normalized' to opcode.
5811  * MonoInst->opcode initially is the IL opcode or some simplification of that 
5812  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
5813  * opcode with value bigger than OP_LAST.
5814  * At this point the IR can be handed over to an interpreter, a dumb code generator
5815  * or to the optimizing code generator that will translate it to SSA form.
5816  *
5817  * Profiling directed optimizations.
5818  * We may compile by default with few or no optimizations and instrument the code
5819  * or the user may indicate what methods to optimize the most either in a config file
5820  * or through repeated runs where the compiler applies offline the optimizations to 
5821  * each method and then decides if it was worth it.
5822  */
5823
5824 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
5825 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
5826 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
5827 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
5828 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
5829 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
5830 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
5831 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
5832
5833 /* offset from br.s -> br like opcodes */
5834 #define BIG_BRANCH_OFFSET 13
5835
5836 static gboolean
5837 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
5838 {
5839         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
5840
5841         return b == NULL || b == bb;
5842 }
5843
5844 static int
5845 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
5846 {
5847         unsigned char *ip = start;
5848         unsigned char *target;
5849         int i;
5850         guint cli_addr;
5851         MonoBasicBlock *bblock;
5852         const MonoOpcode *opcode;
5853
5854         while (ip < end) {
5855                 cli_addr = ip - start;
5856                 i = mono_opcode_value ((const guint8 **)&ip, end);
5857                 if (i < 0)
5858                         UNVERIFIED;
5859                 opcode = &mono_opcodes [i];
5860                 switch (opcode->argument) {
5861                 case MonoInlineNone:
5862                         ip++; 
5863                         break;
5864                 case MonoInlineString:
5865                 case MonoInlineType:
5866                 case MonoInlineField:
5867                 case MonoInlineMethod:
5868                 case MonoInlineTok:
5869                 case MonoInlineSig:
5870                 case MonoShortInlineR:
5871                 case MonoInlineI:
5872                         ip += 5;
5873                         break;
5874                 case MonoInlineVar:
5875                         ip += 3;
5876                         break;
5877                 case MonoShortInlineVar:
5878                 case MonoShortInlineI:
5879                         ip += 2;
5880                         break;
5881                 case MonoShortInlineBrTarget:
5882                         target = start + cli_addr + 2 + (signed char)ip [1];
5883                         GET_BBLOCK (cfg, bblock, target);
5884                         ip += 2;
5885                         if (ip < end)
5886                                 GET_BBLOCK (cfg, bblock, ip);
5887                         break;
5888                 case MonoInlineBrTarget:
5889                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
5890                         GET_BBLOCK (cfg, bblock, target);
5891                         ip += 5;
5892                         if (ip < end)
5893                                 GET_BBLOCK (cfg, bblock, ip);
5894                         break;
5895                 case MonoInlineSwitch: {
5896                         guint32 n = read32 (ip + 1);
5897                         guint32 j;
5898                         ip += 5;
5899                         cli_addr += 5 + 4 * n;
5900                         target = start + cli_addr;
5901                         GET_BBLOCK (cfg, bblock, target);
5902                         
5903                         for (j = 0; j < n; ++j) {
5904                                 target = start + cli_addr + (gint32)read32 (ip);
5905                                 GET_BBLOCK (cfg, bblock, target);
5906                                 ip += 4;
5907                         }
5908                         break;
5909                 }
5910                 case MonoInlineR:
5911                 case MonoInlineI8:
5912                         ip += 9;
5913                         break;
5914                 default:
5915                         g_assert_not_reached ();
5916                 }
5917
5918                 if (i == CEE_THROW) {
5919                         unsigned char *bb_start = ip - 1;
5920                         
5921                         /* Find the start of the bblock containing the throw */
5922                         bblock = NULL;
5923                         while ((bb_start >= start) && !bblock) {
5924                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
5925                                 bb_start --;
5926                         }
5927                         if (bblock)
5928                                 bblock->out_of_line = 1;
5929                 }
5930         }
5931         return 0;
5932 unverified:
5933 exception_exit:
5934         *pos = ip;
5935         return 1;
5936 }
5937
5938 static inline MonoMethod *
5939 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
5940 {
5941         MonoMethod *method;
5942
5943         if (m->wrapper_type != MONO_WRAPPER_NONE) {
5944                 method = mono_method_get_wrapper_data (m, token);
5945                 if (context)
5946                         method = mono_class_inflate_generic_method (method, context);
5947         } else {
5948                 method = mono_get_method_full (m->klass->image, token, klass, context);
5949         }
5950
5951         return method;
5952 }
5953
5954 static inline MonoMethod *
5955 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
5956 {
5957         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
5958
5959         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
5960                 return NULL;
5961
5962         return method;
5963 }
5964
5965 static inline MonoClass*
5966 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
5967 {
5968         MonoClass *klass;
5969
5970         if (method->wrapper_type != MONO_WRAPPER_NONE) {
5971                 klass = mono_method_get_wrapper_data (method, token);
5972                 if (context)
5973                         klass = mono_class_inflate_generic_class (klass, context);
5974         } else {
5975                 klass = mono_class_get_full (method->klass->image, token, context);
5976         }
5977         if (klass)
5978                 mono_class_init (klass);
5979         return klass;
5980 }
5981
5982 static inline MonoMethodSignature*
5983 mini_get_signature (MonoMethod *method, guint32 token, MonoGenericContext *context)
5984 {
5985         MonoMethodSignature *fsig;
5986
5987         if (method->wrapper_type != MONO_WRAPPER_NONE) {
5988                 MonoError error;
5989
5990                 fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
5991                 if (context) {
5992                         fsig = mono_inflate_generic_signature (fsig, context, &error);
5993                         // FIXME:
5994                         g_assert (mono_error_ok (&error));
5995                 }
5996         } else {
5997                 fsig = mono_metadata_parse_signature (method->klass->image, token);
5998         }
5999         return fsig;
6000 }
6001
6002 /*
6003  * Returns TRUE if the JIT should abort inlining because "callee"
6004  * is influenced by security attributes.
6005  */
6006 static
6007 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
6008 {
6009         guint32 result;
6010         
6011         if ((cfg->method != caller) && mono_security_method_has_declsec (callee)) {
6012                 return TRUE;
6013         }
6014         
6015         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
6016         if (result == MONO_JIT_SECURITY_OK)
6017                 return FALSE;
6018
6019         if (result == MONO_JIT_LINKDEMAND_ECMA) {
6020                 /* Generate code to throw a SecurityException before the actual call/link */
6021                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6022                 MonoInst *args [2];
6023
6024                 NEW_ICONST (cfg, args [0], 4);
6025                 NEW_METHODCONST (cfg, args [1], caller);
6026                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
6027         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
6028                  /* don't hide previous results */
6029                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
6030                 cfg->exception_data = result;
6031                 return TRUE;
6032         }
6033         
6034         return FALSE;
6035 }
6036
6037 static MonoMethod*
6038 throw_exception (void)
6039 {
6040         static MonoMethod *method = NULL;
6041
6042         if (!method) {
6043                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
6044                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
6045         }
6046         g_assert (method);
6047         return method;
6048 }
6049
6050 static void
6051 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
6052 {
6053         MonoMethod *thrower = throw_exception ();
6054         MonoInst *args [1];
6055
6056         EMIT_NEW_PCONST (cfg, args [0], ex);
6057         mono_emit_method_call (cfg, thrower, args, NULL);
6058 }
6059
6060 /*
6061  * Return the original method is a wrapper is specified. We can only access 
6062  * the custom attributes from the original method.
6063  */
6064 static MonoMethod*
6065 get_original_method (MonoMethod *method)
6066 {
6067         if (method->wrapper_type == MONO_WRAPPER_NONE)
6068                 return method;
6069
6070         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
6071         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
6072                 return NULL;
6073
6074         /* in other cases we need to find the original method */
6075         return mono_marshal_method_from_wrapper (method);
6076 }
6077
6078 static void
6079 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
6080                                           MonoBasicBlock *bblock, unsigned char *ip)
6081 {
6082         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6083         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
6084         if (ex)
6085                 emit_throw_exception (cfg, ex);
6086 }
6087
6088 static void
6089 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
6090                                          MonoBasicBlock *bblock, unsigned char *ip)
6091 {
6092         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
6093         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
6094         if (ex)
6095                 emit_throw_exception (cfg, ex);
6096 }
6097
6098 /*
6099  * Check that the IL instructions at ip are the array initialization
6100  * sequence and return the pointer to the data and the size.
6101  */
6102 static const char*
6103 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
6104 {
6105         /*
6106          * newarr[System.Int32]
6107          * dup
6108          * ldtoken field valuetype ...
6109          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
6110          */
6111         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
6112                 guint32 token = read32 (ip + 7);
6113                 guint32 field_token = read32 (ip + 2);
6114                 guint32 field_index = field_token & 0xffffff;
6115                 guint32 rva;
6116                 const char *data_ptr;
6117                 int size = 0;
6118                 MonoMethod *cmethod;
6119                 MonoClass *dummy_class;
6120                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
6121                 int dummy_align;
6122
6123                 if (!field)
6124                         return NULL;
6125
6126                 *out_field_token = field_token;
6127
6128                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
6129                 if (!cmethod)
6130                         return NULL;
6131                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
6132                         return NULL;
6133                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
6134                 case MONO_TYPE_BOOLEAN:
6135                 case MONO_TYPE_I1:
6136                 case MONO_TYPE_U1:
6137                         size = 1; break;
6138                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
6139 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
6140                 case MONO_TYPE_CHAR:
6141                 case MONO_TYPE_I2:
6142                 case MONO_TYPE_U2:
6143                         size = 2; break;
6144                 case MONO_TYPE_I4:
6145                 case MONO_TYPE_U4:
6146                 case MONO_TYPE_R4:
6147                         size = 4; break;
6148                 case MONO_TYPE_R8:
6149 #ifdef ARM_FPU_FPA
6150                         return NULL; /* stupid ARM FP swapped format */
6151 #endif
6152                 case MONO_TYPE_I8:
6153                 case MONO_TYPE_U8:
6154                         size = 8; break;
6155 #endif
6156                 default:
6157                         return NULL;
6158                 }
6159                 size *= len;
6160                 if (size > mono_type_size (field->type, &dummy_align))
6161                     return NULL;
6162                 *out_size = size;
6163                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
6164                 if (!method->klass->image->dynamic) {
6165                         field_index = read32 (ip + 2) & 0xffffff;
6166                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
6167                         data_ptr = mono_image_rva_map (method->klass->image, rva);
6168                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
6169                         /* for aot code we do the lookup on load */
6170                         if (aot && data_ptr)
6171                                 return GUINT_TO_POINTER (rva);
6172                 } else {
6173                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
6174                         g_assert (!aot);
6175                         data_ptr = mono_field_get_data (field);
6176                 }
6177                 return data_ptr;
6178         }
6179         return NULL;
6180 }
6181
6182 static void
6183 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
6184 {
6185         char *method_fname = mono_method_full_name (method, TRUE);
6186         char *method_code;
6187         MonoMethodHeader *header = mono_method_get_header (method);
6188
6189         if (header->code_size == 0)
6190                 method_code = g_strdup ("method body is empty.");
6191         else
6192                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
6193         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6194         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
6195         g_free (method_fname);
6196         g_free (method_code);
6197         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
6198 }
6199
6200 static void
6201 set_exception_object (MonoCompile *cfg, MonoException *exception)
6202 {
6203         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
6204         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
6205         cfg->exception_ptr = exception;
6206 }
6207
6208 static void
6209 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
6210 {
6211         MonoInst *ins;
6212         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
6213         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
6214                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
6215                 /* Optimize reg-reg moves away */
6216                 /* 
6217                  * Can't optimize other opcodes, since sp[0] might point to
6218                  * the last ins of a decomposed opcode.
6219                  */
6220                 sp [0]->dreg = (cfg)->locals [n]->dreg;
6221         } else {
6222                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
6223         }
6224 }
6225
6226 /*
6227  * ldloca inhibits many optimizations so try to get rid of it in common
6228  * cases.
6229  */
6230 static inline unsigned char *
6231 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
6232 {
6233         int local, token;
6234         MonoClass *klass;
6235
6236         if (size == 1) {
6237                 local = ip [1];
6238                 ip += 2;
6239         } else {
6240                 local = read16 (ip + 2);
6241                 ip += 4;
6242         }
6243         
6244         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
6245                 gboolean skip = FALSE;
6246
6247                 /* From the INITOBJ case */
6248                 token = read32 (ip + 2);
6249                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
6250                 CHECK_TYPELOAD (klass);
6251                 if (mini_type_is_reference (cfg, &klass->byval_arg)) {
6252                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [local]->dreg, NULL);
6253                 } else if (MONO_TYPE_ISSTRUCT (&klass->byval_arg)) {
6254                         MONO_EMIT_NEW_VZERO (cfg, cfg->locals [local]->dreg, klass);
6255                 } else {
6256                         skip = TRUE;
6257                 }
6258                         
6259                 if (!skip)
6260                         return ip + 6;
6261         }
6262 load_error:
6263         return NULL;
6264 }
6265
6266 static gboolean
6267 is_exception_class (MonoClass *class)
6268 {
6269         while (class) {
6270                 if (class == mono_defaults.exception_class)
6271                         return TRUE;
6272                 class = class->parent;
6273         }
6274         return FALSE;
6275 }
6276
6277 /*
6278  * is_jit_optimizer_disabled:
6279  *
6280  *   Determine whenever M's assembly has a DebuggableAttribute with the
6281  * IsJITOptimizerDisabled flag set.
6282  */
6283 static gboolean
6284 is_jit_optimizer_disabled (MonoMethod *m)
6285 {
6286         MonoAssembly *ass = m->klass->image->assembly;
6287         MonoCustomAttrInfo* attrs;
6288         static MonoClass *klass;
6289         int i;
6290         gboolean val = FALSE;
6291
6292         g_assert (ass);
6293         if (ass->jit_optimizer_disabled_inited)
6294                 return ass->jit_optimizer_disabled;
6295
6296         if (!klass)
6297                 klass = mono_class_from_name (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
6298         if (!klass) {
6299                 /* Linked away */
6300                 ass->jit_optimizer_disabled = FALSE;
6301                 mono_memory_barrier ();
6302                 ass->jit_optimizer_disabled_inited = TRUE;
6303                 return FALSE;
6304         }
6305
6306         attrs = mono_custom_attrs_from_assembly (ass);
6307         if (attrs) {
6308                 for (i = 0; i < attrs->num_attrs; ++i) {
6309                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
6310                         const gchar *p;
6311                         int len;
6312                         MonoMethodSignature *sig;
6313
6314                         if (!attr->ctor || attr->ctor->klass != klass)
6315                                 continue;
6316                         /* Decode the attribute. See reflection.c */
6317                         len = attr->data_size;
6318                         p = (const char*)attr->data;
6319                         g_assert (read16 (p) == 0x0001);
6320                         p += 2;
6321
6322                         // FIXME: Support named parameters
6323                         sig = mono_method_signature (attr->ctor);
6324                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
6325                                 continue;
6326                         /* Two boolean arguments */
6327                         p ++;
6328                         val = *p;
6329                 }
6330                 mono_custom_attrs_free (attrs);
6331         }
6332
6333         ass->jit_optimizer_disabled = val;
6334         mono_memory_barrier ();
6335         ass->jit_optimizer_disabled_inited = TRUE;
6336
6337         return val;
6338 }
6339
6340 static gboolean
6341 is_supported_tail_call (MonoCompile *cfg, MonoMethod *method, MonoMethod *cmethod, MonoMethodSignature *fsig)
6342 {
6343         gboolean supported_tail_call;
6344         int i;
6345
6346 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6347         supported_tail_call = MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
6348 #else
6349         supported_tail_call = mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6350 #endif
6351
6352         for (i = 0; i < fsig->param_count; ++i) {
6353                 if (fsig->params [i]->byref || fsig->params [i]->type == MONO_TYPE_PTR || fsig->params [i]->type == MONO_TYPE_FNPTR)
6354                         /* These can point to the current method's stack */
6355                         supported_tail_call = FALSE;
6356         }
6357         if (fsig->hasthis && cmethod->klass->valuetype)
6358                 /* this might point to the current method's stack */
6359                 supported_tail_call = FALSE;
6360         if (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
6361                 supported_tail_call = FALSE;
6362         if (cfg->method->save_lmf)
6363                 supported_tail_call = FALSE;
6364         if (cmethod->wrapper_type && cmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD)
6365                 supported_tail_call = FALSE;
6366
6367         /* Debugging support */
6368 #if 0
6369         if (supported_tail_call) {
6370                 if (!mono_debug_count ())
6371                         supported_tail_call = FALSE;
6372         }
6373 #endif
6374
6375         return supported_tail_call;
6376 }
6377
6378 /* the JIT intercepts ldflda instructions to the tlsdata field in ThreadLocal<T> and redirects
6379  * it to the thread local value based on the tls_offset field. Every other kind of access to
6380  * the field causes an assert.
6381  */
6382 static gboolean
6383 is_magic_tls_access (MonoClassField *field)
6384 {
6385         if (strcmp (field->name, "tlsdata"))
6386                 return FALSE;
6387         if (strcmp (field->parent->name, "ThreadLocal`1"))
6388                 return FALSE;
6389         return field->parent->image == mono_defaults.corlib;
6390 }
6391
6392 /* emits the code needed to access a managed tls var (like ThreadStatic)
6393  * with the value of the tls offset in offset_reg. thread_ins represents the MonoInternalThread
6394  * pointer for the current thread.
6395  * Returns the MonoInst* representing the address of the tls var.
6396  */
6397 static MonoInst*
6398 emit_managed_static_data_access (MonoCompile *cfg, MonoInst *thread_ins, int offset_reg)
6399 {
6400         MonoInst *addr;
6401         int static_data_reg, array_reg, dreg;
6402         int offset2_reg, idx_reg;
6403         // inlined access to the tls data
6404         // idx = (offset >> 24) - 1;
6405         // return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
6406         static_data_reg = alloc_ireg (cfg);
6407         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
6408         idx_reg = alloc_ireg (cfg);
6409         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
6410         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
6411         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
6412         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
6413         array_reg = alloc_ireg (cfg);
6414         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
6415         offset2_reg = alloc_ireg (cfg);
6416         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
6417         dreg = alloc_ireg (cfg);
6418         EMIT_NEW_BIALU (cfg, addr, OP_PADD, dreg, array_reg, offset2_reg);
6419         return addr;
6420 }
6421
6422 /*
6423  * redirect access to the tlsdata field to the tls var given by the tls_offset field.
6424  * this address is cached per-method in cached_tls_addr.
6425  */
6426 static MonoInst*
6427 create_magic_tls_access (MonoCompile *cfg, MonoClassField *tls_field, MonoInst **cached_tls_addr, MonoInst *thread_local)
6428 {
6429         MonoInst *load, *addr, *temp, *store, *thread_ins;
6430         MonoClassField *offset_field;
6431
6432         if (*cached_tls_addr) {
6433                 EMIT_NEW_TEMPLOAD (cfg, addr, (*cached_tls_addr)->inst_c0);
6434                 return addr;
6435         }
6436         thread_ins = mono_get_thread_intrinsic (cfg);
6437         offset_field = mono_class_get_field_from_name (tls_field->parent, "tls_offset");
6438
6439         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, offset_field->type, thread_local->dreg, offset_field->offset);
6440         if (thread_ins) {
6441                 MONO_ADD_INS (cfg->cbb, thread_ins);
6442         } else {
6443                 MonoMethod *thread_method;
6444                 thread_method = mono_class_get_method_from_name (mono_get_thread_class(), "CurrentInternalThread_internal", 0);
6445                 thread_ins = mono_emit_method_call (cfg, thread_method, NULL, NULL);
6446         }
6447         addr = emit_managed_static_data_access (cfg, thread_ins, load->dreg);
6448         addr->klass = mono_class_from_mono_type (tls_field->type);
6449         addr->type = STACK_MP;
6450         *cached_tls_addr = temp = mono_compile_create_var (cfg, type_from_stack_type (addr), OP_LOCAL);
6451         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, addr);
6452
6453         EMIT_NEW_TEMPLOAD (cfg, addr, temp->inst_c0);
6454         return addr;
6455 }
6456
6457 /*
6458  * mono_method_to_ir:
6459  *
6460  *   Translate the .net IL into linear IR.
6461  */
6462 int
6463 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
6464                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
6465                    guint inline_offset, gboolean is_virtual_call)
6466 {
6467         MonoError error;
6468         MonoInst *ins, **sp, **stack_start;
6469         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
6470         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
6471         MonoMethod *cmethod, *method_definition;
6472         MonoInst **arg_array;
6473         MonoMethodHeader *header;
6474         MonoImage *image;
6475         guint32 token, ins_flag;
6476         MonoClass *klass;
6477         MonoClass *constrained_call = NULL;
6478         unsigned char *ip, *end, *target, *err_pos;
6479         static double r8_0 = 0.0;
6480         MonoMethodSignature *sig;
6481         MonoGenericContext *generic_context = NULL;
6482         MonoGenericContainer *generic_container = NULL;
6483         MonoType **param_types;
6484         int i, n, start_new_bblock, dreg;
6485         int num_calls = 0, inline_costs = 0;
6486         int breakpoint_id = 0;
6487         guint num_args;
6488         MonoBoolean security, pinvoke;
6489         MonoSecurityManager* secman = NULL;
6490         MonoDeclSecurityActions actions;
6491         GSList *class_inits = NULL;
6492         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
6493         int context_used;
6494         gboolean init_locals, seq_points, skip_dead_blocks;
6495         gboolean disable_inline, sym_seq_points = FALSE;
6496         MonoInst *cached_tls_addr = NULL;
6497         MonoDebugMethodInfo *minfo;
6498         MonoBitSet *seq_point_locs = NULL;
6499         MonoBitSet *seq_point_set_locs = NULL;
6500
6501         disable_inline = is_jit_optimizer_disabled (method);
6502
6503         /* serialization and xdomain stuff may need access to private fields and methods */
6504         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
6505         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
6506         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
6507         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
6508         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
6509         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
6510
6511         dont_verify |= mono_security_smcs_hack_enabled ();
6512
6513         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
6514         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
6515         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
6516         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
6517         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_STELEMREF;
6518
6519         image = method->klass->image;
6520         header = mono_method_get_header (method);
6521         if (!header) {
6522                 MonoLoaderError *error;
6523
6524                 if ((error = mono_loader_get_last_error ())) {
6525                         mono_cfg_set_exception (cfg, error->exception_type);
6526                 } else {
6527                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
6528                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
6529                 }
6530                 goto exception_exit;
6531         }
6532         generic_container = mono_method_get_generic_container (method);
6533         sig = mono_method_signature (method);
6534         num_args = sig->hasthis + sig->param_count;
6535         ip = (unsigned char*)header->code;
6536         cfg->cil_start = ip;
6537         end = ip + header->code_size;
6538         cfg->stat_cil_code_size += header->code_size;
6539         init_locals = header->init_locals;
6540
6541         seq_points = cfg->gen_seq_points && cfg->method == method;
6542 #ifdef PLATFORM_ANDROID
6543         seq_points &= cfg->method->wrapper_type == MONO_WRAPPER_NONE;
6544 #endif
6545
6546         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
6547                 /* We could hit a seq point before attaching to the JIT (#8338) */
6548                 seq_points = FALSE;
6549         }
6550
6551         if (cfg->gen_seq_points && cfg->method == method) {
6552                 minfo = mono_debug_lookup_method (method);
6553                 if (minfo) {
6554                         int i, n_il_offsets;
6555                         int *il_offsets;
6556                         int *line_numbers;
6557
6558                         mono_debug_symfile_get_line_numbers_full (minfo, NULL, NULL, &n_il_offsets, &il_offsets, &line_numbers, NULL, NULL);
6559                         seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (cfg->mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
6560                         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);
6561                         sym_seq_points = TRUE;
6562                         for (i = 0; i < n_il_offsets; ++i) {
6563                                 if (il_offsets [i] < header->code_size)
6564                                         mono_bitset_set_fast (seq_point_locs, il_offsets [i]);
6565                         }
6566                         g_free (il_offsets);
6567                         g_free (line_numbers);
6568                 }
6569         }
6570
6571         /* 
6572          * Methods without init_locals set could cause asserts in various passes
6573          * (#497220).
6574          */
6575         init_locals = TRUE;
6576
6577         method_definition = method;
6578         while (method_definition->is_inflated) {
6579                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
6580                 method_definition = imethod->declaring;
6581         }
6582
6583         /* SkipVerification is not allowed if core-clr is enabled */
6584         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
6585                 dont_verify = TRUE;
6586                 dont_verify_stloc = TRUE;
6587         }
6588
6589         if (mono_debug_using_mono_debugger ())
6590                 cfg->keep_cil_nops = TRUE;
6591
6592         if (sig->is_inflated)
6593                 generic_context = mono_method_get_context (method);
6594         else if (generic_container)
6595                 generic_context = &generic_container->context;
6596         cfg->generic_context = generic_context;
6597
6598         if (!cfg->generic_sharing_context)
6599                 g_assert (!sig->has_type_parameters);
6600
6601         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
6602                 g_assert (method->is_inflated);
6603                 g_assert (mono_method_get_context (method)->method_inst);
6604         }
6605         if (method->is_inflated && mono_method_get_context (method)->method_inst)
6606                 g_assert (sig->generic_param_count);
6607
6608         if (cfg->method == method) {
6609                 cfg->real_offset = 0;
6610         } else {
6611                 cfg->real_offset = inline_offset;
6612         }
6613
6614         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
6615         cfg->cil_offset_to_bb_len = header->code_size;
6616
6617         cfg->current_method = method;
6618
6619         if (cfg->verbose_level > 2)
6620                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
6621
6622         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
6623         if (sig->hasthis)
6624                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
6625         for (n = 0; n < sig->param_count; ++n)
6626                 param_types [n + sig->hasthis] = sig->params [n];
6627         cfg->arg_types = param_types;
6628
6629         dont_inline = g_list_prepend (dont_inline, method);
6630         if (cfg->method == method) {
6631
6632                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
6633                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
6634
6635                 /* ENTRY BLOCK */
6636                 NEW_BBLOCK (cfg, start_bblock);
6637                 cfg->bb_entry = start_bblock;
6638                 start_bblock->cil_code = NULL;
6639                 start_bblock->cil_length = 0;
6640 #if defined(__native_client_codegen__)
6641                 MONO_INST_NEW (cfg, ins, OP_NACL_GC_SAFE_POINT);
6642                 ins->dreg = alloc_dreg (cfg, STACK_I4);
6643                 MONO_ADD_INS (start_bblock, ins);
6644 #endif
6645
6646                 /* EXIT BLOCK */
6647                 NEW_BBLOCK (cfg, end_bblock);
6648                 cfg->bb_exit = end_bblock;
6649                 end_bblock->cil_code = NULL;
6650                 end_bblock->cil_length = 0;
6651                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
6652                 g_assert (cfg->num_bblocks == 2);
6653
6654                 arg_array = cfg->args;
6655
6656                 if (header->num_clauses) {
6657                         cfg->spvars = g_hash_table_new (NULL, NULL);
6658                         cfg->exvars = g_hash_table_new (NULL, NULL);
6659                 }
6660                 /* handle exception clauses */
6661                 for (i = 0; i < header->num_clauses; ++i) {
6662                         MonoBasicBlock *try_bb;
6663                         MonoExceptionClause *clause = &header->clauses [i];
6664                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
6665                         try_bb->real_offset = clause->try_offset;
6666                         try_bb->try_start = TRUE;
6667                         try_bb->region = ((i + 1) << 8) | clause->flags;
6668                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
6669                         tblock->real_offset = clause->handler_offset;
6670                         tblock->flags |= BB_EXCEPTION_HANDLER;
6671
6672                         link_bblock (cfg, try_bb, tblock);
6673
6674                         if (*(ip + clause->handler_offset) == CEE_POP)
6675                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
6676
6677                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
6678                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
6679                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
6680                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6681                                 MONO_ADD_INS (tblock, ins);
6682
6683                                 if (seq_points && clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY) {
6684                                         /* finally clauses already have a seq point */
6685                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
6686                                         MONO_ADD_INS (tblock, ins);
6687                                 }
6688
6689                                 /* todo: is a fault block unsafe to optimize? */
6690                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
6691                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
6692                         }
6693
6694
6695                         /*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);
6696                           while (p < end) {
6697                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
6698                           }*/
6699                         /* catch and filter blocks get the exception object on the stack */
6700                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
6701                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6702                                 MonoInst *dummy_use;
6703
6704                                 /* mostly like handle_stack_args (), but just sets the input args */
6705                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
6706                                 tblock->in_scount = 1;
6707                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6708                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6709
6710                                 /* 
6711                                  * Add a dummy use for the exvar so its liveness info will be
6712                                  * correct.
6713                                  */
6714                                 cfg->cbb = tblock;
6715                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
6716                                 
6717                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
6718                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
6719                                         tblock->flags |= BB_EXCEPTION_HANDLER;
6720                                         tblock->real_offset = clause->data.filter_offset;
6721                                         tblock->in_scount = 1;
6722                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
6723                                         /* The filter block shares the exvar with the handler block */
6724                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
6725                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
6726                                         MONO_ADD_INS (tblock, ins);
6727                                 }
6728                         }
6729
6730                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
6731                                         clause->data.catch_class &&
6732                                         cfg->generic_sharing_context &&
6733                                         mono_class_check_context_used (clause->data.catch_class)) {
6734                                 /*
6735                                  * In shared generic code with catch
6736                                  * clauses containing type variables
6737                                  * the exception handling code has to
6738                                  * be able to get to the rgctx.
6739                                  * Therefore we have to make sure that
6740                                  * the vtable/mrgctx argument (for
6741                                  * static or generic methods) or the
6742                                  * "this" argument (for non-static
6743                                  * methods) are live.
6744                                  */
6745                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
6746                                                 mini_method_get_context (method)->method_inst ||
6747                                                 method->klass->valuetype) {
6748                                         mono_get_vtable_var (cfg);
6749                                 } else {
6750                                         MonoInst *dummy_use;
6751
6752                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
6753                                 }
6754                         }
6755                 }
6756         } else {
6757                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
6758                 cfg->cbb = start_bblock;
6759                 cfg->args = arg_array;
6760                 mono_save_args (cfg, sig, inline_args);
6761         }
6762
6763         /* FIRST CODE BLOCK */
6764         NEW_BBLOCK (cfg, bblock);
6765         bblock->cil_code = ip;
6766         cfg->cbb = bblock;
6767         cfg->ip = ip;
6768
6769         ADD_BBLOCK (cfg, bblock);
6770
6771         if (cfg->method == method) {
6772                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
6773                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
6774                         MONO_INST_NEW (cfg, ins, OP_BREAK);
6775                         MONO_ADD_INS (bblock, ins);
6776                 }
6777         }
6778
6779         if (mono_security_cas_enabled ())
6780                 secman = mono_security_manager_get_methods ();
6781
6782         security = (secman && mono_security_method_has_declsec (method));
6783         /* at this point having security doesn't mean we have any code to generate */
6784         if (security && (cfg->method == method)) {
6785                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
6786                  * And we do not want to enter the next section (with allocation) if we
6787                  * have nothing to generate */
6788                 security = mono_declsec_get_demands (method, &actions);
6789         }
6790
6791         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
6792         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
6793         if (pinvoke) {
6794                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
6795                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6796                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
6797
6798                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
6799                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
6800                                 pinvoke = FALSE;
6801                         }
6802                         if (custom)
6803                                 mono_custom_attrs_free (custom);
6804
6805                         if (pinvoke) {
6806                                 custom = mono_custom_attrs_from_class (wrapped->klass);
6807                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
6808                                         pinvoke = FALSE;
6809                                 }
6810                                 if (custom)
6811                                         mono_custom_attrs_free (custom);
6812                         }
6813                 } else {
6814                         /* not a P/Invoke after all */
6815                         pinvoke = FALSE;
6816                 }
6817         }
6818         
6819         if ((init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
6820                 /* we use a separate basic block for the initialization code */
6821                 NEW_BBLOCK (cfg, init_localsbb);
6822                 cfg->bb_init = init_localsbb;
6823                 init_localsbb->real_offset = cfg->real_offset;
6824                 start_bblock->next_bb = init_localsbb;
6825                 init_localsbb->next_bb = bblock;
6826                 link_bblock (cfg, start_bblock, init_localsbb);
6827                 link_bblock (cfg, init_localsbb, bblock);
6828                 
6829                 cfg->cbb = init_localsbb;
6830         } else {
6831                 start_bblock->next_bb = bblock;
6832                 link_bblock (cfg, start_bblock, bblock);
6833         }
6834
6835         if (cfg->gsharedvt && cfg->method == method) {
6836                 MonoGSharedVtMethodInfo *info;
6837                 MonoInst *var, *locals_var;
6838                 int dreg;
6839
6840                 info = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoGSharedVtMethodInfo));
6841                 info->method = cfg->method;
6842                 // FIXME: Free this
6843                 info->entries = g_ptr_array_new ();
6844                 cfg->gsharedvt_info = info;
6845
6846                 var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6847                 /* prevent it from being register allocated */
6848                 //var->flags |= MONO_INST_INDIRECT;
6849                 cfg->gsharedvt_info_var = var;
6850
6851                 ins = emit_get_rgctx_gsharedvt_method (cfg, mini_method_check_context_used (cfg, method), method, info);
6852                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, var->dreg, ins->dreg);
6853
6854                 /* Allocate locals */
6855                 locals_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6856                 /* prevent it from being register allocated */
6857                 //locals_var->flags |= MONO_INST_INDIRECT;
6858                 cfg->gsharedvt_locals_var = locals_var;
6859
6860                 dreg = alloc_ireg (cfg);
6861                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, dreg, var->dreg, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, locals_size));
6862
6863                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
6864                 ins->dreg = locals_var->dreg;
6865                 ins->sreg1 = dreg;
6866                 MONO_ADD_INS (cfg->cbb, ins);
6867                 cfg->gsharedvt_locals_var_ins = ins;
6868                 
6869                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
6870                 /*
6871                 if (init_locals)
6872                         ins->flags |= MONO_INST_INIT;
6873                 */
6874         }
6875
6876         /* at this point we know, if security is TRUE, that some code needs to be generated */
6877         if (security && (cfg->method == method)) {
6878                 MonoInst *args [2];
6879
6880                 cfg->stat_cas_demand_generation++;
6881
6882                 if (actions.demand.blob) {
6883                         /* Add code for SecurityAction.Demand */
6884                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
6885                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
6886                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
6887                         mono_emit_method_call (cfg, secman->demand, args, NULL);
6888                 }
6889                 if (actions.noncasdemand.blob) {
6890                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
6891                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
6892                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
6893                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
6894                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
6895                         mono_emit_method_call (cfg, secman->demand, args, NULL);
6896                 }
6897                 if (actions.demandchoice.blob) {
6898                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
6899                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
6900                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
6901                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
6902                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
6903                 }
6904         }
6905
6906         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
6907         if (pinvoke) {
6908                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
6909         }
6910
6911         if (mono_security_core_clr_enabled ()) {
6912                 /* check if this is native code, e.g. an icall or a p/invoke */
6913                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
6914                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
6915                         if (wrapped) {
6916                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
6917                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
6918
6919                                 /* if this ia a native call then it can only be JITted from platform code */
6920                                 if ((icall || pinvk) && method->klass && method->klass->image) {
6921                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
6922                                                 MonoException *ex = icall ? mono_get_exception_security () : 
6923                                                         mono_get_exception_method_access ();
6924                                                 emit_throw_exception (cfg, ex);
6925                                         }
6926                                 }
6927                         }
6928                 }
6929         }
6930
6931         CHECK_CFG_EXCEPTION;
6932
6933         if (header->code_size == 0)
6934                 UNVERIFIED;
6935
6936         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
6937                 ip = err_pos;
6938                 UNVERIFIED;
6939         }
6940
6941         if (cfg->method == method)
6942                 mono_debug_init_method (cfg, bblock, breakpoint_id);
6943
6944         for (n = 0; n < header->num_locals; ++n) {
6945                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
6946                         UNVERIFIED;
6947         }
6948         class_inits = NULL;
6949
6950         /* We force the vtable variable here for all shared methods
6951            for the possibility that they might show up in a stack
6952            trace where their exact instantiation is needed. */
6953         if (cfg->generic_sharing_context && method == cfg->method) {
6954                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
6955                                 mini_method_get_context (method)->method_inst ||
6956                                 method->klass->valuetype) {
6957                         mono_get_vtable_var (cfg);
6958                 } else {
6959                         /* FIXME: Is there a better way to do this?
6960                            We need the variable live for the duration
6961                            of the whole method. */
6962                         cfg->args [0]->flags |= MONO_INST_INDIRECT;
6963                 }
6964         }
6965
6966         /* add a check for this != NULL to inlined methods */
6967         if (is_virtual_call) {
6968                 MonoInst *arg_ins;
6969
6970                 NEW_ARGLOAD (cfg, arg_ins, 0);
6971                 MONO_ADD_INS (cfg->cbb, arg_ins);
6972                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
6973         }
6974
6975         skip_dead_blocks = !dont_verify;
6976         if (skip_dead_blocks) {
6977                 original_bb = bb = mono_basic_block_split (method, &error);
6978                 if (!mono_error_ok (&error)) {
6979                         mono_error_cleanup (&error);
6980                         UNVERIFIED;
6981                 }
6982                 g_assert (bb);
6983         }
6984
6985         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
6986         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
6987
6988         ins_flag = 0;
6989         start_new_bblock = 0;
6990         cfg->cbb = bblock;
6991         while (ip < end) {
6992                 if (cfg->method == method)
6993                         cfg->real_offset = ip - header->code;
6994                 else
6995                         cfg->real_offset = inline_offset;
6996                 cfg->ip = ip;
6997
6998                 context_used = 0;
6999                 
7000                 if (start_new_bblock) {
7001                         bblock->cil_length = ip - bblock->cil_code;
7002                         if (start_new_bblock == 2) {
7003                                 g_assert (ip == tblock->cil_code);
7004                         } else {
7005                                 GET_BBLOCK (cfg, tblock, ip);
7006                         }
7007                         bblock->next_bb = tblock;
7008                         bblock = tblock;
7009                         cfg->cbb = bblock;
7010                         start_new_bblock = 0;
7011                         for (i = 0; i < bblock->in_scount; ++i) {
7012                                 if (cfg->verbose_level > 3)
7013                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7014                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7015                                 *sp++ = ins;
7016                         }
7017                         if (class_inits)
7018                                 g_slist_free (class_inits);
7019                         class_inits = NULL;
7020                 } else {
7021                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
7022                                 link_bblock (cfg, bblock, tblock);
7023                                 if (sp != stack_start) {
7024                                         handle_stack_args (cfg, stack_start, sp - stack_start);
7025                                         sp = stack_start;
7026                                         CHECK_UNVERIFIABLE (cfg);
7027                                 }
7028                                 bblock->next_bb = tblock;
7029                                 bblock = tblock;
7030                                 cfg->cbb = bblock;
7031                                 for (i = 0; i < bblock->in_scount; ++i) {
7032                                         if (cfg->verbose_level > 3)
7033                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
7034                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
7035                                         *sp++ = ins;
7036                                 }
7037                                 g_slist_free (class_inits);
7038                                 class_inits = NULL;
7039                         }
7040                 }
7041
7042                 if (skip_dead_blocks) {
7043                         int ip_offset = ip - header->code;
7044
7045                         if (ip_offset == bb->end)
7046                                 bb = bb->next;
7047
7048                         if (bb->dead) {
7049                                 int op_size = mono_opcode_size (ip, end);
7050                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
7051
7052                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
7053
7054                                 if (ip_offset + op_size == bb->end) {
7055                                         MONO_INST_NEW (cfg, ins, OP_NOP);
7056                                         MONO_ADD_INS (bblock, ins);
7057                                         start_new_bblock = 1;
7058                                 }
7059
7060                                 ip += op_size;
7061                                 continue;
7062                         }
7063                 }
7064                 /*
7065                  * Sequence points are points where the debugger can place a breakpoint.
7066                  * Currently, we generate these automatically at points where the IL
7067                  * stack is empty.
7068                  */
7069                 if (seq_points && ((sp == stack_start) || (sym_seq_points && mono_bitset_test_fast (seq_point_locs, ip - header->code)))) {
7070                         /*
7071                          * Make methods interruptable at the beginning, and at the targets of
7072                          * backward branches.
7073                          * Also, do this at the start of every bblock in methods with clauses too,
7074                          * to be able to handle instructions with inprecise control flow like
7075                          * throw/endfinally.
7076                          * Backward branches are handled at the end of method-to-ir ().
7077                          */
7078                         gboolean intr_loc = ip == header->code || (!cfg->cbb->last_ins && cfg->header->num_clauses);
7079
7080                         /* Avoid sequence points on empty IL like .volatile */
7081                         // FIXME: Enable this
7082                         //if (!(cfg->cbb->last_ins && cfg->cbb->last_ins->opcode == OP_SEQ_POINT)) {
7083                         NEW_SEQ_POINT (cfg, ins, ip - header->code, intr_loc);
7084                         if (sp != stack_start)
7085                                 ins->flags |= MONO_INST_NONEMPTY_STACK;
7086                         MONO_ADD_INS (cfg->cbb, ins);
7087
7088                         if (sym_seq_points)
7089                                 mono_bitset_set_fast (seq_point_set_locs, ip - header->code);
7090                 }
7091
7092                 bblock->real_offset = cfg->real_offset;
7093
7094                 if ((cfg->method == method) && cfg->coverage_info) {
7095                         guint32 cil_offset = ip - header->code;
7096                         cfg->coverage_info->data [cil_offset].cil_code = ip;
7097
7098                         /* TODO: Use an increment here */
7099 #if defined(TARGET_X86)
7100                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
7101                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
7102                         ins->inst_imm = 1;
7103                         MONO_ADD_INS (cfg->cbb, ins);
7104 #else
7105                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
7106                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
7107 #endif
7108                 }
7109
7110                 if (cfg->verbose_level > 3)
7111                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
7112
7113                 switch (*ip) {
7114                 case CEE_NOP:
7115                         if (seq_points && !sym_seq_points && sp != stack_start) {
7116                                 /*
7117                                  * The C# compiler uses these nops to notify the JIT that it should
7118                                  * insert seq points.
7119                                  */
7120                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, FALSE);
7121                                 MONO_ADD_INS (cfg->cbb, ins);
7122                         }
7123                         if (cfg->keep_cil_nops)
7124                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
7125                         else
7126                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7127                         ip++;
7128                         MONO_ADD_INS (bblock, ins);
7129                         break;
7130                 case CEE_BREAK:
7131                         if (should_insert_brekpoint (cfg->method)) {
7132                                 ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
7133                         } else {
7134                                 MONO_INST_NEW (cfg, ins, OP_NOP);
7135                         }
7136                         ip++;
7137                         MONO_ADD_INS (bblock, ins);
7138                         break;
7139                 case CEE_LDARG_0:
7140                 case CEE_LDARG_1:
7141                 case CEE_LDARG_2:
7142                 case CEE_LDARG_3:
7143                         CHECK_STACK_OVF (1);
7144                         n = (*ip)-CEE_LDARG_0;
7145                         CHECK_ARG (n);
7146                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7147                         ip++;
7148                         *sp++ = ins;
7149                         break;
7150                 case CEE_LDLOC_0:
7151                 case CEE_LDLOC_1:
7152                 case CEE_LDLOC_2:
7153                 case CEE_LDLOC_3:
7154                         CHECK_STACK_OVF (1);
7155                         n = (*ip)-CEE_LDLOC_0;
7156                         CHECK_LOCAL (n);
7157                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7158                         ip++;
7159                         *sp++ = ins;
7160                         break;
7161                 case CEE_STLOC_0:
7162                 case CEE_STLOC_1:
7163                 case CEE_STLOC_2:
7164                 case CEE_STLOC_3: {
7165                         CHECK_STACK (1);
7166                         n = (*ip)-CEE_STLOC_0;
7167                         CHECK_LOCAL (n);
7168                         --sp;
7169                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
7170                                 UNVERIFIED;
7171                         emit_stloc_ir (cfg, sp, header, n);
7172                         ++ip;
7173                         inline_costs += 1;
7174                         break;
7175                         }
7176                 case CEE_LDARG_S:
7177                         CHECK_OPSIZE (2);
7178                         CHECK_STACK_OVF (1);
7179                         n = ip [1];
7180                         CHECK_ARG (n);
7181                         EMIT_NEW_ARGLOAD (cfg, ins, n);
7182                         *sp++ = ins;
7183                         ip += 2;
7184                         break;
7185                 case CEE_LDARGA_S:
7186                         CHECK_OPSIZE (2);
7187                         CHECK_STACK_OVF (1);
7188                         n = ip [1];
7189                         CHECK_ARG (n);
7190                         NEW_ARGLOADA (cfg, ins, n);
7191                         MONO_ADD_INS (cfg->cbb, ins);
7192                         *sp++ = ins;
7193                         ip += 2;
7194                         break;
7195                 case CEE_STARG_S:
7196                         CHECK_OPSIZE (2);
7197                         CHECK_STACK (1);
7198                         --sp;
7199                         n = ip [1];
7200                         CHECK_ARG (n);
7201                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
7202                                 UNVERIFIED;
7203                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
7204                         ip += 2;
7205                         break;
7206                 case CEE_LDLOC_S:
7207                         CHECK_OPSIZE (2);
7208                         CHECK_STACK_OVF (1);
7209                         n = ip [1];
7210                         CHECK_LOCAL (n);
7211                         EMIT_NEW_LOCLOAD (cfg, ins, n);
7212                         *sp++ = ins;
7213                         ip += 2;
7214                         break;
7215                 case CEE_LDLOCA_S: {
7216                         unsigned char *tmp_ip;
7217                         CHECK_OPSIZE (2);
7218                         CHECK_STACK_OVF (1);
7219                         CHECK_LOCAL (ip [1]);
7220
7221                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
7222                                 ip = tmp_ip;
7223                                 inline_costs += 1;
7224                                 break;
7225                         }
7226
7227                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
7228                         *sp++ = ins;
7229                         ip += 2;
7230                         break;
7231                 }
7232                 case CEE_STLOC_S:
7233                         CHECK_OPSIZE (2);
7234                         CHECK_STACK (1);
7235                         --sp;
7236                         CHECK_LOCAL (ip [1]);
7237                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
7238                                 UNVERIFIED;
7239                         emit_stloc_ir (cfg, sp, header, ip [1]);
7240                         ip += 2;
7241                         inline_costs += 1;
7242                         break;
7243                 case CEE_LDNULL:
7244                         CHECK_STACK_OVF (1);
7245                         EMIT_NEW_PCONST (cfg, ins, NULL);
7246                         ins->type = STACK_OBJ;
7247                         ++ip;
7248                         *sp++ = ins;
7249                         break;
7250                 case CEE_LDC_I4_M1:
7251                         CHECK_STACK_OVF (1);
7252                         EMIT_NEW_ICONST (cfg, ins, -1);
7253                         ++ip;
7254                         *sp++ = ins;
7255                         break;
7256                 case CEE_LDC_I4_0:
7257                 case CEE_LDC_I4_1:
7258                 case CEE_LDC_I4_2:
7259                 case CEE_LDC_I4_3:
7260                 case CEE_LDC_I4_4:
7261                 case CEE_LDC_I4_5:
7262                 case CEE_LDC_I4_6:
7263                 case CEE_LDC_I4_7:
7264                 case CEE_LDC_I4_8:
7265                         CHECK_STACK_OVF (1);
7266                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
7267                         ++ip;
7268                         *sp++ = ins;
7269                         break;
7270                 case CEE_LDC_I4_S:
7271                         CHECK_OPSIZE (2);
7272                         CHECK_STACK_OVF (1);
7273                         ++ip;
7274                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
7275                         ++ip;
7276                         *sp++ = ins;
7277                         break;
7278                 case CEE_LDC_I4:
7279                         CHECK_OPSIZE (5);
7280                         CHECK_STACK_OVF (1);
7281                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
7282                         ip += 5;
7283                         *sp++ = ins;
7284                         break;
7285                 case CEE_LDC_I8:
7286                         CHECK_OPSIZE (9);
7287                         CHECK_STACK_OVF (1);
7288                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
7289                         ins->type = STACK_I8;
7290                         ins->dreg = alloc_dreg (cfg, STACK_I8);
7291                         ++ip;
7292                         ins->inst_l = (gint64)read64 (ip);
7293                         MONO_ADD_INS (bblock, ins);
7294                         ip += 8;
7295                         *sp++ = ins;
7296                         break;
7297                 case CEE_LDC_R4: {
7298                         float *f;
7299                         gboolean use_aotconst = FALSE;
7300
7301 #ifdef TARGET_POWERPC
7302                         /* FIXME: Clean this up */
7303                         if (cfg->compile_aot)
7304                                 use_aotconst = TRUE;
7305 #endif
7306
7307                         /* FIXME: we should really allocate this only late in the compilation process */
7308                         f = mono_domain_alloc (cfg->domain, sizeof (float));
7309                         CHECK_OPSIZE (5);
7310                         CHECK_STACK_OVF (1);
7311
7312                         if (use_aotconst) {
7313                                 MonoInst *cons;
7314                                 int dreg;
7315
7316                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
7317
7318                                 dreg = alloc_freg (cfg);
7319                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
7320                                 ins->type = STACK_R8;
7321                         } else {
7322                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
7323                                 ins->type = STACK_R8;
7324                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7325                                 ins->inst_p0 = f;
7326                                 MONO_ADD_INS (bblock, ins);
7327                         }
7328                         ++ip;
7329                         readr4 (ip, f);
7330                         ip += 4;
7331                         *sp++ = ins;                    
7332                         break;
7333                 }
7334                 case CEE_LDC_R8: {
7335                         double *d;
7336                         gboolean use_aotconst = FALSE;
7337
7338 #ifdef TARGET_POWERPC
7339                         /* FIXME: Clean this up */
7340                         if (cfg->compile_aot)
7341                                 use_aotconst = TRUE;
7342 #endif
7343
7344                         /* FIXME: we should really allocate this only late in the compilation process */
7345                         d = mono_domain_alloc (cfg->domain, sizeof (double));
7346                         CHECK_OPSIZE (9);
7347                         CHECK_STACK_OVF (1);
7348
7349                         if (use_aotconst) {
7350                                 MonoInst *cons;
7351                                 int dreg;
7352
7353                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
7354
7355                                 dreg = alloc_freg (cfg);
7356                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
7357                                 ins->type = STACK_R8;
7358                         } else {
7359                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
7360                                 ins->type = STACK_R8;
7361                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
7362                                 ins->inst_p0 = d;
7363                                 MONO_ADD_INS (bblock, ins);
7364                         }
7365                         ++ip;
7366                         readr8 (ip, d);
7367                         ip += 8;
7368                         *sp++ = ins;
7369                         break;
7370                 }
7371                 case CEE_DUP: {
7372                         MonoInst *temp, *store;
7373                         CHECK_STACK (1);
7374                         CHECK_STACK_OVF (1);
7375                         sp--;
7376                         ins = *sp;
7377
7378                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
7379                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
7380
7381                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7382                         *sp++ = ins;
7383
7384                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
7385                         *sp++ = ins;
7386
7387                         ++ip;
7388                         inline_costs += 2;
7389                         break;
7390                 }
7391                 case CEE_POP:
7392                         CHECK_STACK (1);
7393                         ip++;
7394                         --sp;
7395
7396 #ifdef TARGET_X86
7397                         if (sp [0]->type == STACK_R8)
7398                                 /* we need to pop the value from the x86 FP stack */
7399                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
7400 #endif
7401                         break;
7402                 case CEE_JMP: {
7403                         MonoCallInst *call;
7404
7405                         INLINE_FAILURE ("jmp");
7406                         GSHAREDVT_FAILURE (*ip);
7407
7408                         CHECK_OPSIZE (5);
7409                         if (stack_start != sp)
7410                                 UNVERIFIED;
7411                         token = read32 (ip + 1);
7412                         /* FIXME: check the signature matches */
7413                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7414
7415                         if (!cmethod || mono_loader_get_last_error ())
7416                                 LOAD_ERROR;
7417  
7418                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
7419                                 GENERIC_SHARING_FAILURE (CEE_JMP);
7420
7421                         if (mono_security_cas_enabled ())
7422                                 CHECK_CFG_EXCEPTION;
7423
7424 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
7425                         {
7426                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
7427                                 int i, n;
7428
7429                                 /* Handle tail calls similarly to calls */
7430                                 n = fsig->param_count + fsig->hasthis;
7431
7432                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
7433                                 call->method = cmethod;
7434                                 call->tail_call = TRUE;
7435                                 call->signature = mono_method_signature (cmethod);
7436                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
7437                                 call->inst.inst_p0 = cmethod;
7438                                 for (i = 0; i < n; ++i)
7439                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
7440
7441                                 mono_arch_emit_call (cfg, call);
7442                                 MONO_ADD_INS (bblock, (MonoInst*)call);
7443                         }
7444 #else
7445                         for (i = 0; i < num_args; ++i)
7446                                 /* Prevent arguments from being optimized away */
7447                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
7448
7449                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
7450                         ins = (MonoInst*)call;
7451                         ins->inst_p0 = cmethod;
7452                         MONO_ADD_INS (bblock, ins);
7453 #endif
7454
7455                         ip += 5;
7456                         start_new_bblock = 1;
7457                         break;
7458                 }
7459                 case CEE_CALLI:
7460                 case CEE_CALL:
7461                 case CEE_CALLVIRT: {
7462                         MonoInst *addr = NULL;
7463                         MonoMethodSignature *fsig = NULL;
7464                         int array_rank = 0;
7465                         int virtual = *ip == CEE_CALLVIRT;
7466                         int calli = *ip == CEE_CALLI;
7467                         gboolean pass_imt_from_rgctx = FALSE;
7468                         MonoInst *imt_arg = NULL;
7469                         MonoInst *keep_this_alive = NULL;
7470                         gboolean pass_vtable = FALSE;
7471                         gboolean pass_mrgctx = FALSE;
7472                         MonoInst *vtable_arg = NULL;
7473                         gboolean check_this = FALSE;
7474                         gboolean supported_tail_call = FALSE;
7475                         gboolean tail_call = FALSE;
7476                         gboolean need_seq_point = FALSE;
7477                         guint32 call_opcode = *ip;
7478                         gboolean emit_widen = TRUE;
7479                         gboolean push_res = TRUE;
7480                         gboolean skip_ret = FALSE;
7481                         gboolean delegate_invoke = FALSE;
7482
7483                         CHECK_OPSIZE (5);
7484                         token = read32 (ip + 1);
7485
7486                         ins = NULL;
7487
7488                         if (calli) {
7489                                 //GSHAREDVT_FAILURE (*ip);
7490                                 cmethod = NULL;
7491                                 CHECK_STACK (1);
7492                                 --sp;
7493                                 addr = *sp;
7494                                 fsig = mini_get_signature (method, token, generic_context);
7495                                 n = fsig->param_count + fsig->hasthis;
7496
7497                                 if (method->dynamic && fsig->pinvoke) {
7498                                         MonoInst *args [3];
7499
7500                                         /*
7501                                          * This is a call through a function pointer using a pinvoke
7502                                          * signature. Have to create a wrapper and call that instead.
7503                                          * FIXME: This is very slow, need to create a wrapper at JIT time
7504                                          * instead based on the signature.
7505                                          */
7506                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
7507                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
7508                                         args [2] = addr;
7509                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
7510                                 }
7511                         } else {
7512                                 MonoMethod *cil_method;
7513
7514                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7515                                 cil_method = cmethod;
7516                                 
7517                                 if (constrained_call) {
7518                                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
7519                                                 if (cfg->verbose_level > 2)
7520                                                         printf ("DM Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7521                                                 if (!((constrained_call->byval_arg.type == MONO_TYPE_VAR ||
7522                                                            constrained_call->byval_arg.type == MONO_TYPE_MVAR) &&
7523                                                           cfg->generic_sharing_context)) {
7524                                                         cmethod = mono_get_method_constrained_with_method (image, cil_method, constrained_call, generic_context);
7525                                                 }
7526                                         } else {
7527                                                 if (cfg->verbose_level > 2)
7528                                                         printf ("Constrained call to %s\n", mono_type_get_full_name (constrained_call));
7529
7530                                                 if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
7531                                                         /* 
7532                                                          * This is needed since get_method_constrained can't find 
7533                                                          * the method in klass representing a type var.
7534                                                          * The type var is guaranteed to be a reference type in this
7535                                                          * case.
7536                                                          */
7537                                                         if (!mini_is_gsharedvt_klass (cfg, constrained_call))
7538                                                                 g_assert (!cmethod->klass->valuetype);
7539                                                 } else {
7540                                                         cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
7541                                                 }
7542                                         }
7543                                 }
7544                                         
7545                                 if (!cmethod || mono_loader_get_last_error ())
7546                                         LOAD_ERROR;
7547                                 if (!dont_verify && !cfg->skip_visibility) {
7548                                         MonoMethod *target_method = cil_method;
7549                                         if (method->is_inflated) {
7550                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
7551                                         }
7552                                         if (!mono_method_can_access_method (method_definition, target_method) &&
7553                                                 !mono_method_can_access_method (method, cil_method))
7554                                                 METHOD_ACCESS_FAILURE;
7555                                 }
7556
7557                                 if (mono_security_core_clr_enabled ())
7558                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
7559
7560                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
7561                                         /* MS.NET seems to silently convert this to a callvirt */
7562                                         virtual = 1;
7563
7564                                 {
7565                                         /*
7566                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
7567                                          * converts to a callvirt.
7568                                          *
7569                                          * tests/bug-515884.il is an example of this behavior
7570                                          */
7571                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
7572                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
7573                                         if (!virtual && mono_class_is_marshalbyref (cmethod->klass) && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
7574                                                 virtual = 1;
7575                                 }
7576
7577                                 if (!cmethod->klass->inited)
7578                                         if (!mono_class_init (cmethod->klass))
7579                                                 TYPE_LOAD_ERROR (cmethod->klass);
7580
7581                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
7582                                     mini_class_is_system_array (cmethod->klass)) {
7583                                         array_rank = cmethod->klass->rank;
7584                                         fsig = mono_method_signature (cmethod);
7585                                 } else {
7586                                         fsig = mono_method_signature (cmethod);
7587
7588                                         if (!fsig)
7589                                                 LOAD_ERROR;
7590
7591                                         if (fsig->pinvoke) {
7592                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
7593                                                         check_for_pending_exc, cfg->compile_aot);
7594                                                 fsig = mono_method_signature (wrapper);
7595                                         } else if (constrained_call) {
7596                                                 fsig = mono_method_signature (cmethod);
7597                                         } else {
7598                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
7599                                         }
7600                                 }
7601
7602                                 mono_save_token_info (cfg, image, token, cil_method);
7603
7604                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7605                                         /*
7606                                          * Need to emit an implicit seq point after every non-void call so single stepping through nested calls like
7607                                          * foo (bar (), baz ())
7608                                          * works correctly. MS does this also:
7609                                          * http://stackoverflow.com/questions/6937198/making-your-net-language-step-correctly-in-the-debugger
7610                                          * The problem with this approach is that the debugger will stop after all calls returning a value,
7611                                          * even for simple cases, like:
7612                                          * int i = foo ();
7613                                          */
7614                                         /* Special case a few common successor opcodes */
7615                                         if (!(ip + 5 < end && (ip [5] == CEE_POP || ip [5] == CEE_NOP)) && !(seq_point_locs && mono_bitset_test_fast (seq_point_locs, ip + 5 - header->code)))
7616                                                 need_seq_point = TRUE;
7617                                 }
7618
7619                                 n = fsig->param_count + fsig->hasthis;
7620
7621                                 /* Don't support calls made using type arguments for now */
7622                                 /*
7623                                 if (cfg->gsharedvt) {
7624                                         if (mini_is_gsharedvt_signature (cfg, fsig))
7625                                                 GSHAREDVT_FAILURE (*ip);
7626                                 }
7627                                 */
7628
7629                                 if (mono_security_cas_enabled ()) {
7630                                         if (check_linkdemand (cfg, method, cmethod))
7631                                                 INLINE_FAILURE ("linkdemand");
7632                                         CHECK_CFG_EXCEPTION;
7633                                 }
7634
7635                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
7636                                         g_assert_not_reached ();
7637                         }
7638
7639                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
7640                                 UNVERIFIED;
7641
7642                         if (!cfg->generic_sharing_context && cmethod)
7643                                 g_assert (!mono_method_check_context_used (cmethod));
7644
7645                         CHECK_STACK (n);
7646
7647                         //g_assert (!virtual || fsig->hasthis);
7648
7649                         sp -= n;
7650
7651                         if (constrained_call) {
7652                                 if (mini_is_gsharedvt_klass (cfg, constrained_call)) {
7653                                         /*
7654                                          * Constrained calls need to behave differently at runtime dependending on whenever the receiver is instantiated as ref type or as a vtype.
7655                                          */
7656                                         if ((cmethod->klass != mono_defaults.object_class) && constrained_call->valuetype && cmethod->klass->valuetype) {
7657                                                 /* The 'Own method' case below */
7658                                         } else if (cmethod->klass->image != mono_defaults.corlib && !(cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) && !cmethod->klass->valuetype) {
7659                                                 /* 'The type parameter is instantiated as a reference type' case below. */
7660                                         } else if (((cmethod->klass == mono_defaults.object_class) || (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE) || (!cmethod->klass->valuetype && cmethod->klass->image != mono_defaults.corlib)) &&
7661                                                            (MONO_TYPE_IS_VOID (fsig->ret) || MONO_TYPE_IS_PRIMITIVE (fsig->ret) || MONO_TYPE_IS_REFERENCE (fsig->ret) || mini_is_gsharedvt_type (cfg, fsig->ret)) &&
7662                                                            (fsig->param_count == 0 || (!fsig->hasthis && fsig->param_count == 1) || (fsig->param_count == 1 && (MONO_TYPE_IS_REFERENCE (fsig->params [0]) || mini_is_gsharedvt_type (cfg, fsig->params [0]))))) {
7663                                                 MonoInst *args [16];
7664
7665                                                 /*
7666                                                  * This case handles calls to
7667                                                  * - object:ToString()/Equals()/GetHashCode(),
7668                                                  * - System.IComparable<T>:CompareTo()
7669                                                  * - System.IEquatable<T>:Equals ()
7670                                                  * plus some simple interface calls enough to support AsyncTaskMethodBuilder.
7671                                                  */
7672
7673                                                 args [0] = sp [0];
7674                                                 if (mono_method_check_context_used (cmethod))
7675                                                         args [1] = emit_get_rgctx_method (cfg, mono_method_check_context_used (cmethod), cmethod, MONO_RGCTX_INFO_METHOD);
7676                                                 else
7677                                                         EMIT_NEW_METHODCONST (cfg, args [1], cmethod);
7678                                                 args [2] = emit_get_rgctx_klass (cfg, mono_class_check_context_used (constrained_call), constrained_call, MONO_RGCTX_INFO_KLASS);
7679
7680                                                 /* !fsig->hasthis is for the wrapper for the Object.GetType () icall */
7681                                                 if (fsig->hasthis && fsig->param_count) {
7682                                                         /* Pass the arguments using a localloc-ed array using the format expected by runtime_invoke () */
7683                                                         MONO_INST_NEW (cfg, ins, OP_LOCALLOC_IMM);
7684                                                         ins->dreg = alloc_preg (cfg);
7685                                                         ins->inst_imm = fsig->param_count * sizeof (mgreg_t);
7686                                                         MONO_ADD_INS (cfg->cbb, ins);
7687                                                         args [4] = ins;
7688
7689                                                         if (mini_is_gsharedvt_type (cfg, fsig->params [0])) {
7690                                                                 int addr_reg;
7691
7692                                                                 args [3] = emit_get_gsharedvt_info_klass (cfg, mono_class_from_mono_type (fsig->params [0]), MONO_RGCTX_INFO_CLASS_BOX_TYPE);
7693
7694                                                                 EMIT_NEW_VARLOADA_VREG (cfg, ins, sp [1]->dreg, fsig->params [0]);
7695                                                                 addr_reg = ins->dreg;
7696                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, addr_reg);
7697                                                         } else {
7698                                                                 EMIT_NEW_ICONST (cfg, args [3], 0);
7699                                                                 EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [4]->dreg, 0, sp [1]->dreg);
7700                                                         }
7701                                                 } else {
7702                                                         EMIT_NEW_ICONST (cfg, args [3], 0);
7703                                                         EMIT_NEW_ICONST (cfg, args [4], 0);
7704                                                 }
7705                                                 ins = mono_emit_jit_icall (cfg, mono_gsharedvt_constrained_call, args);
7706                                                 emit_widen = FALSE;
7707
7708                                                 if (mini_is_gsharedvt_type (cfg, fsig->ret)) {
7709                                                         ins = handle_unbox_gsharedvt (cfg, mono_class_from_mono_type (fsig->ret), ins, &bblock);
7710                                                 } else if (MONO_TYPE_IS_PRIMITIVE (fsig->ret)) {
7711                                                         MonoInst *add;
7712
7713                                                         /* Unbox */
7714                                                         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_MP), ins->dreg, sizeof (MonoObject));
7715                                                         MONO_ADD_INS (cfg->cbb, add);
7716                                                         /* Load value */
7717                                                         NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, add->dreg, 0);
7718                                                         MONO_ADD_INS (cfg->cbb, ins);
7719                                                         /* ins represents the call result */
7720                                                 }
7721
7722                                                 goto call_end;
7723                                         } else {
7724                                                 GSHAREDVT_FAILURE (*ip);
7725                                         }
7726                                 }
7727                                 /*
7728                                  * We have the `constrained.' prefix opcode.
7729                                  */
7730                                 if (constrained_call->valuetype && (cmethod->klass == mono_defaults.object_class || cmethod->klass == mono_defaults.enum_class->parent || cmethod->klass == mono_defaults.enum_class)) {
7731                                         /*
7732                                          * The type parameter is instantiated as a valuetype,
7733                                          * but that type doesn't override the method we're
7734                                          * calling, so we need to box `this'.
7735                                          */
7736                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
7737                                         ins->klass = constrained_call;
7738                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
7739                                         CHECK_CFG_EXCEPTION;
7740                                 } else if (!constrained_call->valuetype) {
7741                                         int dreg = alloc_ireg_ref (cfg);
7742
7743                                         /*
7744                                          * The type parameter is instantiated as a reference
7745                                          * type.  We have a managed pointer on the stack, so
7746                                          * we need to dereference it here.
7747                                          */
7748                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
7749                                         ins->type = STACK_OBJ;
7750                                         sp [0] = ins;
7751                                 } else {
7752                                         if (cmethod->klass->valuetype) {
7753                                                 /* Own method */
7754                                         } else {
7755                                                 /* Interface method */
7756                                                 int ioffset, slot;
7757
7758                                                 mono_class_setup_vtable (constrained_call);
7759                                                 CHECK_TYPELOAD (constrained_call);
7760                                                 ioffset = mono_class_interface_offset (constrained_call, cmethod->klass);
7761                                                 if (ioffset == -1)
7762                                                         TYPE_LOAD_ERROR (constrained_call);
7763                                                 slot = mono_method_get_vtable_slot (cmethod);
7764                                                 if (slot == -1)
7765                                                         TYPE_LOAD_ERROR (cmethod->klass);
7766                                                 cmethod = constrained_call->vtable [ioffset + slot];
7767
7768                                                 if (cmethod->klass == mono_defaults.enum_class) {
7769                                                         /* Enum implements some interfaces, so treat this as the first case */
7770                                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
7771                                                         ins->klass = constrained_call;
7772                                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call), &bblock);
7773                                                         CHECK_CFG_EXCEPTION;
7774                                                 }
7775                                         }
7776                                         virtual = 0;
7777                                 }
7778                                 constrained_call = NULL;
7779                         }
7780
7781                         if (!calli && check_call_signature (cfg, fsig, sp))
7782                                 UNVERIFIED;
7783
7784 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
7785                         if (cmethod && (cmethod->klass->parent == mono_defaults.multicastdelegate_class) && !strcmp (cmethod->name, "Invoke"))
7786                                 delegate_invoke = TRUE;
7787 #endif
7788
7789                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_sharable_method (cfg, cmethod, fsig, sp))) {
7790                                 bblock = cfg->cbb;
7791                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7792                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
7793                                         emit_widen = FALSE;
7794                                 }
7795
7796                                 goto call_end;
7797                         }
7798
7799                         /* 
7800                          * If the callee is a shared method, then its static cctor
7801                          * might not get called after the call was patched.
7802                          */
7803                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
7804                                 emit_generic_class_init (cfg, cmethod->klass);
7805                                 CHECK_TYPELOAD (cmethod->klass);
7806                         }
7807
7808                         if (cmethod)
7809                                 check_method_sharing (cfg, cmethod, &pass_vtable, &pass_mrgctx);
7810
7811                         if (cfg->generic_sharing_context && cmethod) {
7812                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
7813
7814                                 context_used = mini_method_check_context_used (cfg, cmethod);
7815
7816                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
7817                                         /* Generic method interface
7818                                            calls are resolved via a
7819                                            helper function and don't
7820                                            need an imt. */
7821                                         if (!cmethod_context || !cmethod_context->method_inst)
7822                                                 pass_imt_from_rgctx = TRUE;
7823                                 }
7824
7825                                 /*
7826                                  * If a shared method calls another
7827                                  * shared method then the caller must
7828                                  * have a generic sharing context
7829                                  * because the magic trampoline
7830                                  * requires it.  FIXME: We shouldn't
7831                                  * have to force the vtable/mrgctx
7832                                  * variable here.  Instead there
7833                                  * should be a flag in the cfg to
7834                                  * request a generic sharing context.
7835                                  */
7836                                 if (context_used &&
7837                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
7838                                         mono_get_vtable_var (cfg);
7839                         }
7840
7841                         if (pass_vtable) {
7842                                 if (context_used) {
7843                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7844                                 } else {
7845                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7846
7847                                         CHECK_TYPELOAD (cmethod->klass);
7848                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7849                                 }
7850                         }
7851
7852                         if (pass_mrgctx) {
7853                                 g_assert (!vtable_arg);
7854
7855                                 if (!cfg->compile_aot) {
7856                                         /* 
7857                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
7858                                          * for type load errors before.
7859                                          */
7860                                         mono_class_setup_vtable (cmethod->klass);
7861                                         CHECK_TYPELOAD (cmethod->klass);
7862                                 }
7863
7864                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7865
7866                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
7867                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
7868                                          MONO_METHOD_IS_FINAL (cmethod)) &&
7869                                         !mono_class_is_marshalbyref (cmethod->klass)) {
7870                                         if (virtual)
7871                                                 check_this = TRUE;
7872                                         virtual = 0;
7873                                 }
7874                         }
7875
7876                         if (pass_imt_from_rgctx) {
7877                                 g_assert (!pass_vtable);
7878                                 g_assert (cmethod);
7879
7880                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
7881                                         cmethod, MONO_RGCTX_INFO_METHOD);
7882                         }
7883
7884                         if (check_this)
7885                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
7886
7887                         /* Calling virtual generic methods */
7888                         if (cmethod && virtual && 
7889                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
7890                             !(MONO_METHOD_IS_FINAL (cmethod) && 
7891                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
7892                             fsig->generic_param_count && 
7893                                 !(cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))) {
7894                                 MonoInst *this_temp, *this_arg_temp, *store;
7895                                 MonoInst *iargs [4];
7896                                 gboolean use_imt = FALSE;
7897
7898                                 g_assert (fsig->is_inflated);
7899
7900                                 /* Prevent inlining of methods that contain indirect calls */
7901                                 INLINE_FAILURE ("virtual generic call");
7902
7903                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
7904                                         GSHAREDVT_FAILURE (*ip);
7905
7906 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
7907                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt)
7908                                         use_imt = TRUE;
7909 #endif
7910
7911                                 if (use_imt) {
7912                                         g_assert (!imt_arg);
7913                                         if (!context_used)
7914                                                 g_assert (cmethod->is_inflated);
7915                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
7916                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
7917                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, sp [0], imt_arg, NULL);
7918                                 } else {
7919                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
7920                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
7921                                         MONO_ADD_INS (bblock, store);
7922
7923                                         /* FIXME: This should be a managed pointer */
7924                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
7925
7926                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
7927                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
7928                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
7929                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
7930                                         addr = mono_emit_jit_icall (cfg,
7931                                                                                                 mono_helper_compile_generic_method, iargs);
7932
7933                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
7934
7935                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, NULL);
7936                                 }
7937
7938                                 goto call_end;
7939                         }
7940
7941                         /*
7942                          * Implement a workaround for the inherent races involved in locking:
7943                          * Monitor.Enter ()
7944                          * try {
7945                          * } finally {
7946                          *    Monitor.Exit ()
7947                          * }
7948                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
7949                          * try block, the Exit () won't be executed, see:
7950                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
7951                          * To work around this, we extend such try blocks to include the last x bytes
7952                          * of the Monitor.Enter () call.
7953                          */
7954                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
7955                                 MonoBasicBlock *tbb;
7956
7957                                 GET_BBLOCK (cfg, tbb, ip + 5);
7958                                 /* 
7959                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
7960                                  * from Monitor.Enter like ArgumentNullException.
7961                                  */
7962                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
7963                                         /* Mark this bblock as needing to be extended */
7964                                         tbb->extend_try_block = TRUE;
7965                                 }
7966                         }
7967
7968                         /* Conversion to a JIT intrinsic */
7969                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
7970                                 bblock = cfg->cbb;
7971                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7972                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
7973                                         emit_widen = FALSE;
7974                                 }
7975                                 goto call_end;
7976                         }
7977
7978                         /* Inlining */
7979                         if (cmethod && (cfg->opt & MONO_OPT_INLINE) &&
7980                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
7981                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
7982                                  !g_list_find (dont_inline, cmethod)) {
7983                                 int costs;
7984                                 gboolean always = FALSE;
7985
7986                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
7987                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
7988                                         /* Prevent inlining of methods that call wrappers */
7989                                         INLINE_FAILURE ("wrapper call");
7990                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
7991                                         always = TRUE;
7992                                 }
7993
7994                                 costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always);
7995                                 if (costs) {
7996                                         cfg->real_offset += 5;
7997                                         bblock = cfg->cbb;
7998
7999                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
8000                                                 /* *sp is already set by inline_method */
8001                                                 sp++;
8002                                                 push_res = FALSE;
8003                                         }
8004
8005                                         inline_costs += costs;
8006
8007                                         goto call_end;
8008                                 }
8009                         }
8010
8011                         /* Tail recursion elimination */
8012                         if ((cfg->opt & MONO_OPT_TAILC) && call_opcode == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
8013                                 gboolean has_vtargs = FALSE;
8014                                 int i;
8015
8016                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8017                                 INLINE_FAILURE ("tail call");
8018
8019                                 /* keep it simple */
8020                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
8021                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
8022                                                 has_vtargs = TRUE;
8023                                 }
8024
8025                                 if (!has_vtargs) {
8026                                         for (i = 0; i < n; ++i)
8027                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8028                                         MONO_INST_NEW (cfg, ins, OP_BR);
8029                                         MONO_ADD_INS (bblock, ins);
8030                                         tblock = start_bblock->out_bb [0];
8031                                         link_bblock (cfg, bblock, tblock);
8032                                         ins->inst_target_bb = tblock;
8033                                         start_new_bblock = 1;
8034
8035                                         /* skip the CEE_RET, too */
8036                                         if (ip_in_bb (cfg, bblock, ip + 5))
8037                                                 skip_ret = TRUE;
8038                                         push_res = FALSE;
8039                                         goto call_end;
8040                                 }
8041                         }
8042
8043                         inline_costs += 10 * num_calls++;
8044
8045                         /*
8046                          * Making generic calls out of gsharedvt methods.
8047                          */
8048                         if (cmethod && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8049                                 MonoRgctxInfoType info_type;
8050
8051                                 if (virtual) {
8052                                         //if (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)
8053                                                 //GSHAREDVT_FAILURE (*ip);
8054                                         // disable for possible remoting calls
8055                                         if (fsig->hasthis && (mono_class_is_marshalbyref (method->klass) || method->klass == mono_defaults.object_class))
8056                                                 GSHAREDVT_FAILURE (*ip);
8057                                         if (fsig->generic_param_count) {
8058                                                 /* virtual generic call */
8059                                                 g_assert (mono_use_imt);
8060                                                 g_assert (!imt_arg);
8061                                                 /* Same as the virtual generic case above */
8062                                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
8063                                                                                                                  cmethod, MONO_RGCTX_INFO_METHOD);
8064                                                 /* This is not needed, as the trampoline code will pass one, and it might be passed in the same reg as the imt arg */
8065                                                 vtable_arg = NULL;
8066                                         }
8067                                 }
8068
8069                                 if (cmethod->klass->rank && cmethod->klass->byval_arg.type != MONO_TYPE_SZARRAY)
8070                                         /* test_0_multi_dim_arrays () in gshared.cs */
8071                                         GSHAREDVT_FAILURE (*ip);
8072
8073                                 if ((cmethod->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (cmethod->name, "Invoke")))
8074                                         keep_this_alive = sp [0];
8075
8076                                 if (virtual && (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))
8077                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE_VIRT;
8078                                 else
8079                                         info_type = MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE;
8080                                 addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, info_type);
8081
8082                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8083                                 goto call_end;
8084                         } else if (calli && cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
8085                                 /*
8086                                  * We pass the address to the gsharedvt trampoline in the rgctx reg
8087                                  */
8088                                 MonoInst *callee = addr;
8089
8090                                 if (method->wrapper_type != MONO_WRAPPER_DELEGATE_INVOKE)
8091                                         /* Not tested */
8092                                         GSHAREDVT_FAILURE (*ip);
8093
8094                                 addr = emit_get_rgctx_sig (cfg, context_used,
8095                                                                                           fsig, MONO_RGCTX_INFO_SIG_GSHAREDVT_OUT_TRAMPOLINE_CALLI);
8096                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, NULL, callee);
8097                                 goto call_end;
8098                         }
8099
8100                         /* Generic sharing */
8101                         /* FIXME: only do this for generic methods if
8102                            they are not shared! */
8103                         if (context_used && !imt_arg && !array_rank && !delegate_invoke &&
8104                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
8105                                  !mono_class_generic_sharing_enabled (cmethod->klass)) &&
8106                                 (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
8107                                  !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
8108                                 INLINE_FAILURE ("gshared");
8109
8110                                 g_assert (cfg->generic_sharing_context && cmethod);
8111                                 g_assert (!addr);
8112
8113                                 /*
8114                                  * We are compiling a call to a
8115                                  * generic method from shared code,
8116                                  * which means that we have to look up
8117                                  * the method in the rgctx and do an
8118                                  * indirect call.
8119                                  */
8120                                 if (fsig->hasthis)
8121                                         MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
8122
8123                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
8124                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8125                                 goto call_end;
8126                         }
8127
8128                         /* Indirect calls */
8129                         if (addr) {
8130                                 if (call_opcode == CEE_CALL)
8131                                         g_assert (context_used);
8132                                 else if (call_opcode == CEE_CALLI)
8133                                         g_assert (!vtable_arg);
8134                                 else
8135                                         /* FIXME: what the hell is this??? */
8136                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
8137                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
8138
8139                                 /* Prevent inlining of methods with indirect calls */
8140                                 INLINE_FAILURE ("indirect call");
8141
8142                                 if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST || addr->opcode == OP_GOT_ENTRY) {
8143                                         int info_type;
8144                                         gpointer info_data;
8145
8146                                         /* 
8147                                          * Instead of emitting an indirect call, emit a direct call
8148                                          * with the contents of the aotconst as the patch info.
8149                                          */
8150                                         if (addr->opcode == OP_PCONST || addr->opcode == OP_AOTCONST) {
8151                                                 info_type = addr->inst_c1;
8152                                                 info_data = addr->inst_p0;
8153                                         } else {
8154                                                 info_type = addr->inst_right->inst_c1;
8155                                                 info_data = addr->inst_right->inst_left;
8156                                         }
8157                                         
8158                                         if (info_type == MONO_PATCH_INFO_ICALL_ADDR || info_type == MONO_PATCH_INFO_JIT_ICALL_ADDR) {
8159                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, info_type, info_data, fsig, sp);
8160                                                 NULLIFY_INS (addr);
8161                                                 goto call_end;
8162                                         }
8163                                 }
8164                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr, imt_arg, vtable_arg);
8165                                 goto call_end;
8166                         }
8167                                         
8168                         /* Array methods */
8169                         if (array_rank) {
8170                                 MonoInst *addr;
8171
8172                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
8173                                         MonoInst *val = sp [fsig->param_count];
8174
8175                                         if (val->type == STACK_OBJ) {
8176                                                 MonoInst *iargs [2];
8177
8178                                                 iargs [0] = sp [0];
8179                                                 iargs [1] = val;
8180                                                 
8181                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
8182                                         }
8183                                         
8184                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
8185                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, val->dreg);
8186                                         if (cfg->gen_write_barriers && val->type == STACK_OBJ && !(val->opcode == OP_PCONST && val->inst_c0 == 0))
8187                                                 emit_write_barrier (cfg, addr, val);
8188                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
8189                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8190
8191                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
8192                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
8193                                         if (!cmethod->klass->element_class->valuetype && !readonly)
8194                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
8195                                         CHECK_TYPELOAD (cmethod->klass);
8196                                         
8197                                         readonly = FALSE;
8198                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
8199                                         ins = addr;
8200                                 } else {
8201                                         g_assert_not_reached ();
8202                                 }
8203
8204                                 emit_widen = FALSE;
8205                                 goto call_end;
8206                         }
8207
8208                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
8209                         if (ins)
8210                                 goto call_end;
8211
8212                         /* Tail prefix / tail call optimization */
8213
8214                         /* FIXME: Enabling TAILC breaks some inlining/stack trace/etc tests */
8215                         /* FIXME: runtime generic context pointer for jumps? */
8216                         /* FIXME: handle this for generic sharing eventually */
8217                         if (cmethod && (ins_flag & MONO_INST_TAILCALL) &&
8218                                 !vtable_arg && !cfg->generic_sharing_context && is_supported_tail_call (cfg, method, cmethod, fsig))
8219                                 supported_tail_call = TRUE;
8220                         if (supported_tail_call) {
8221                                 if (call_opcode != CEE_CALL)
8222                                         supported_tail_call = FALSE;
8223                         }
8224
8225                         if (supported_tail_call) {
8226                                 MonoCallInst *call;
8227
8228                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
8229                                 INLINE_FAILURE ("tail call");
8230
8231                                 //printf ("HIT: %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
8232
8233                                 if (ARCH_USE_OP_TAIL_CALL) {
8234                                         /* Handle tail calls similarly to normal calls */
8235                                         tail_call = TRUE;
8236                                 } else {
8237                                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
8238                                         call->tail_call = TRUE;
8239                                         call->method = cmethod;
8240                                         call->signature = mono_method_signature (cmethod);
8241
8242                                         /*
8243                                          * We implement tail calls by storing the actual arguments into the 
8244                                          * argument variables, then emitting a CEE_JMP.
8245                                          */
8246                                         for (i = 0; i < n; ++i) {
8247                                                 /* Prevent argument from being register allocated */
8248                                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
8249                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
8250                                         }
8251                                         ins = (MonoInst*)call;
8252                                         ins->inst_p0 = cmethod;
8253                                         ins->inst_p1 = arg_array [0];
8254                                         MONO_ADD_INS (bblock, ins);
8255                                         link_bblock (cfg, bblock, end_bblock);                  
8256                                         start_new_bblock = 1;
8257
8258                                         // FIXME: Eliminate unreachable epilogs
8259
8260                                         /*
8261                                          * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8262                                          * only reachable from this call.
8263                                          */
8264                                         GET_BBLOCK (cfg, tblock, ip + 5);
8265                                         if (tblock == bblock || tblock->in_count == 0)
8266                                                 skip_ret = TRUE;
8267                                         push_res = FALSE;
8268
8269                                         goto call_end;
8270                                 }
8271                         }
8272
8273                         /* 
8274                          * Synchronized wrappers.
8275                          * Its hard to determine where to replace a method with its synchronized
8276                          * wrapper without causing an infinite recursion. The current solution is
8277                          * to add the synchronized wrapper in the trampolines, and to
8278                          * change the called method to a dummy wrapper, and resolve that wrapper
8279                          * to the real method in mono_jit_compile_method ().
8280                          */
8281                         if (cfg->method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
8282                                 MonoMethod *orig = mono_marshal_method_from_wrapper (cfg->method);
8283                                 if (cmethod == orig || (cmethod->is_inflated && mono_method_get_declaring_generic_method (cmethod) == orig))
8284                                         cmethod = mono_marshal_get_synchronized_inner_wrapper (cmethod);
8285                         }
8286
8287                         /* Common call */
8288                         INLINE_FAILURE ("call");
8289                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, tail_call, sp, virtual ? sp [0] : NULL,
8290                                                                                           imt_arg, vtable_arg);
8291
8292                         if (tail_call) {
8293                                 link_bblock (cfg, bblock, end_bblock);                  
8294                                 start_new_bblock = 1;
8295
8296                                 // FIXME: Eliminate unreachable epilogs
8297
8298                                 /*
8299                                  * OP_TAILCALL has no return value, so skip the CEE_RET if it is
8300                                  * only reachable from this call.
8301                                  */
8302                                 GET_BBLOCK (cfg, tblock, ip + 5);
8303                                 if (tblock == bblock || tblock->in_count == 0)
8304                                         skip_ret = TRUE;
8305                                 push_res = FALSE;
8306                         }
8307
8308                         call_end:
8309
8310                         /* End of call, INS should contain the result of the call, if any */
8311
8312                         if (push_res && !MONO_TYPE_IS_VOID (fsig->ret)) {
8313                                 g_assert (ins);
8314                                 if (emit_widen)
8315                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
8316                                 else
8317                                         *sp++ = ins;
8318                         }
8319
8320                         if (keep_this_alive) {
8321                                 MonoInst *dummy_use;
8322
8323                                 /* See mono_emit_method_call_full () */
8324                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, keep_this_alive);
8325                         }
8326
8327                         CHECK_CFG_EXCEPTION;
8328
8329                         ip += 5;
8330                         if (skip_ret) {
8331                                 g_assert (*ip == CEE_RET);
8332                                 ip += 1;
8333                         }
8334                         ins_flag = 0;
8335                         constrained_call = NULL;
8336                         if (need_seq_point)
8337                                 emit_seq_point (cfg, method, ip, FALSE, TRUE);
8338                         break;
8339                 }
8340                 case CEE_RET:
8341                         if (cfg->method != method) {
8342                                 /* return from inlined method */
8343                                 /* 
8344                                  * If in_count == 0, that means the ret is unreachable due to
8345                                  * being preceeded by a throw. In that case, inline_method () will
8346                                  * handle setting the return value 
8347                                  * (test case: test_0_inline_throw ()).
8348                                  */
8349                                 if (return_var && cfg->cbb->in_count) {
8350                                         MonoType *ret_type = mono_method_signature (method)->ret;
8351
8352                                         MonoInst *store;
8353                                         CHECK_STACK (1);
8354                                         --sp;
8355
8356                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8357                                                 UNVERIFIED;
8358
8359                                         //g_assert (returnvar != -1);
8360                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
8361                                         cfg->ret_var_set = TRUE;
8362                                 } 
8363                         } else {
8364                                 if (cfg->ret) {
8365                                         MonoType *ret_type = mono_method_signature (method)->ret;
8366
8367                                         if (seq_points && !sym_seq_points) {
8368                                                 /* 
8369                                                  * Place a seq point here too even through the IL stack is not
8370                                                  * empty, so a step over on
8371                                                  * call <FOO>
8372                                                  * ret
8373                                                  * will work correctly.
8374                                                  */
8375                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
8376                                                 MONO_ADD_INS (cfg->cbb, ins);
8377                                         }
8378
8379                                         g_assert (!return_var);
8380                                         CHECK_STACK (1);
8381                                         --sp;
8382
8383                                         if ((method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD || method->wrapper_type == MONO_WRAPPER_NONE) && target_type_is_incompatible (cfg, ret_type, *sp))
8384                                                 UNVERIFIED;
8385
8386                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
8387                                                 MonoInst *ret_addr;
8388
8389                                                 if (!cfg->vret_addr) {
8390                                                         MonoInst *ins;
8391
8392                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
8393                                                 } else {
8394                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
8395
8396                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
8397                                                         ins->klass = mono_class_from_mono_type (ret_type);
8398                                                 }
8399                                         } else {
8400 #ifdef MONO_ARCH_SOFT_FLOAT_FALLBACK
8401                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
8402                                                         MonoInst *iargs [1];
8403                                                         MonoInst *conv;
8404
8405                                                         iargs [0] = *sp;
8406                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
8407                                                         mono_arch_emit_setret (cfg, method, conv);
8408                                                 } else {
8409                                                         mono_arch_emit_setret (cfg, method, *sp);
8410                                                 }
8411 #else
8412                                                 mono_arch_emit_setret (cfg, method, *sp);
8413 #endif
8414                                         }
8415                                 }
8416                         }
8417                         if (sp != stack_start)
8418                                 UNVERIFIED;
8419                         MONO_INST_NEW (cfg, ins, OP_BR);
8420                         ip++;
8421                         ins->inst_target_bb = end_bblock;
8422                         MONO_ADD_INS (bblock, ins);
8423                         link_bblock (cfg, bblock, end_bblock);
8424                         start_new_bblock = 1;
8425                         break;
8426                 case CEE_BR_S:
8427                         CHECK_OPSIZE (2);
8428                         MONO_INST_NEW (cfg, ins, OP_BR);
8429                         ip++;
8430                         target = ip + 1 + (signed char)(*ip);
8431                         ++ip;
8432                         GET_BBLOCK (cfg, tblock, target);
8433                         link_bblock (cfg, bblock, tblock);
8434                         ins->inst_target_bb = tblock;
8435                         if (sp != stack_start) {
8436                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8437                                 sp = stack_start;
8438                                 CHECK_UNVERIFIABLE (cfg);
8439                         }
8440                         MONO_ADD_INS (bblock, ins);
8441                         start_new_bblock = 1;
8442                         inline_costs += BRANCH_COST;
8443                         break;
8444                 case CEE_BEQ_S:
8445                 case CEE_BGE_S:
8446                 case CEE_BGT_S:
8447                 case CEE_BLE_S:
8448                 case CEE_BLT_S:
8449                 case CEE_BNE_UN_S:
8450                 case CEE_BGE_UN_S:
8451                 case CEE_BGT_UN_S:
8452                 case CEE_BLE_UN_S:
8453                 case CEE_BLT_UN_S:
8454                         CHECK_OPSIZE (2);
8455                         CHECK_STACK (2);
8456                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
8457                         ip++;
8458                         target = ip + 1 + *(signed char*)ip;
8459                         ip++;
8460
8461                         ADD_BINCOND (NULL);
8462
8463                         sp = stack_start;
8464                         inline_costs += BRANCH_COST;
8465                         break;
8466                 case CEE_BR:
8467                         CHECK_OPSIZE (5);
8468                         MONO_INST_NEW (cfg, ins, OP_BR);
8469                         ip++;
8470
8471                         target = ip + 4 + (gint32)read32(ip);
8472                         ip += 4;
8473                         GET_BBLOCK (cfg, tblock, target);
8474                         link_bblock (cfg, bblock, tblock);
8475                         ins->inst_target_bb = tblock;
8476                         if (sp != stack_start) {
8477                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8478                                 sp = stack_start;
8479                                 CHECK_UNVERIFIABLE (cfg);
8480                         }
8481
8482                         MONO_ADD_INS (bblock, ins);
8483
8484                         start_new_bblock = 1;
8485                         inline_costs += BRANCH_COST;
8486                         break;
8487                 case CEE_BRFALSE_S:
8488                 case CEE_BRTRUE_S:
8489                 case CEE_BRFALSE:
8490                 case CEE_BRTRUE: {
8491                         MonoInst *cmp;
8492                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
8493                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
8494                         guint32 opsize = is_short ? 1 : 4;
8495
8496                         CHECK_OPSIZE (opsize);
8497                         CHECK_STACK (1);
8498                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
8499                                 UNVERIFIED;
8500                         ip ++;
8501                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
8502                         ip += opsize;
8503
8504                         sp--;
8505
8506                         GET_BBLOCK (cfg, tblock, target);
8507                         link_bblock (cfg, bblock, tblock);
8508                         GET_BBLOCK (cfg, tblock, ip);
8509                         link_bblock (cfg, bblock, tblock);
8510
8511                         if (sp != stack_start) {
8512                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8513                                 CHECK_UNVERIFIABLE (cfg);
8514                         }
8515
8516                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
8517                         cmp->sreg1 = sp [0]->dreg;
8518                         type_from_op (cmp, sp [0], NULL);
8519                         CHECK_TYPE (cmp);
8520
8521 #if SIZEOF_REGISTER == 4
8522                         if (cmp->opcode == OP_LCOMPARE_IMM) {
8523                                 /* Convert it to OP_LCOMPARE */
8524                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
8525                                 ins->type = STACK_I8;
8526                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
8527                                 ins->inst_l = 0;
8528                                 MONO_ADD_INS (bblock, ins);
8529                                 cmp->opcode = OP_LCOMPARE;
8530                                 cmp->sreg2 = ins->dreg;
8531                         }
8532 #endif
8533                         MONO_ADD_INS (bblock, cmp);
8534
8535                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
8536                         type_from_op (ins, sp [0], NULL);
8537                         MONO_ADD_INS (bblock, ins);
8538                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
8539                         GET_BBLOCK (cfg, tblock, target);
8540                         ins->inst_true_bb = tblock;
8541                         GET_BBLOCK (cfg, tblock, ip);
8542                         ins->inst_false_bb = tblock;
8543                         start_new_bblock = 2;
8544
8545                         sp = stack_start;
8546                         inline_costs += BRANCH_COST;
8547                         break;
8548                 }
8549                 case CEE_BEQ:
8550                 case CEE_BGE:
8551                 case CEE_BGT:
8552                 case CEE_BLE:
8553                 case CEE_BLT:
8554                 case CEE_BNE_UN:
8555                 case CEE_BGE_UN:
8556                 case CEE_BGT_UN:
8557                 case CEE_BLE_UN:
8558                 case CEE_BLT_UN:
8559                         CHECK_OPSIZE (5);
8560                         CHECK_STACK (2);
8561                         MONO_INST_NEW (cfg, ins, *ip);
8562                         ip++;
8563                         target = ip + 4 + (gint32)read32(ip);
8564                         ip += 4;
8565
8566                         ADD_BINCOND (NULL);
8567
8568                         sp = stack_start;
8569                         inline_costs += BRANCH_COST;
8570                         break;
8571                 case CEE_SWITCH: {
8572                         MonoInst *src1;
8573                         MonoBasicBlock **targets;
8574                         MonoBasicBlock *default_bblock;
8575                         MonoJumpInfoBBTable *table;
8576                         int offset_reg = alloc_preg (cfg);
8577                         int target_reg = alloc_preg (cfg);
8578                         int table_reg = alloc_preg (cfg);
8579                         int sum_reg = alloc_preg (cfg);
8580                         gboolean use_op_switch;
8581
8582                         CHECK_OPSIZE (5);
8583                         CHECK_STACK (1);
8584                         n = read32 (ip + 1);
8585                         --sp;
8586                         src1 = sp [0];
8587                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
8588                                 UNVERIFIED;
8589
8590                         ip += 5;
8591                         CHECK_OPSIZE (n * sizeof (guint32));
8592                         target = ip + n * sizeof (guint32);
8593
8594                         GET_BBLOCK (cfg, default_bblock, target);
8595                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
8596
8597                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
8598                         for (i = 0; i < n; ++i) {
8599                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
8600                                 targets [i] = tblock;
8601                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
8602                                 ip += 4;
8603                         }
8604
8605                         if (sp != stack_start) {
8606                                 /* 
8607                                  * Link the current bb with the targets as well, so handle_stack_args
8608                                  * will set their in_stack correctly.
8609                                  */
8610                                 link_bblock (cfg, bblock, default_bblock);
8611                                 for (i = 0; i < n; ++i)
8612                                         link_bblock (cfg, bblock, targets [i]);
8613
8614                                 handle_stack_args (cfg, stack_start, sp - stack_start);
8615                                 sp = stack_start;
8616                                 CHECK_UNVERIFIABLE (cfg);
8617                         }
8618
8619                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
8620                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
8621                         bblock = cfg->cbb;
8622
8623                         for (i = 0; i < n; ++i)
8624                                 link_bblock (cfg, bblock, targets [i]);
8625
8626                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
8627                         table->table = targets;
8628                         table->table_size = n;
8629
8630                         use_op_switch = FALSE;
8631 #ifdef TARGET_ARM
8632                         /* ARM implements SWITCH statements differently */
8633                         /* FIXME: Make it use the generic implementation */
8634                         if (!cfg->compile_aot)
8635                                 use_op_switch = TRUE;
8636 #endif
8637
8638                         if (COMPILE_LLVM (cfg))
8639                                 use_op_switch = TRUE;
8640
8641                         cfg->cbb->has_jump_table = 1;
8642
8643                         if (use_op_switch) {
8644                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
8645                                 ins->sreg1 = src1->dreg;
8646                                 ins->inst_p0 = table;
8647                                 ins->inst_many_bb = targets;
8648                                 ins->klass = GUINT_TO_POINTER (n);
8649                                 MONO_ADD_INS (cfg->cbb, ins);
8650                         } else {
8651                                 if (sizeof (gpointer) == 8)
8652                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
8653                                 else
8654                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
8655
8656 #if SIZEOF_REGISTER == 8
8657                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
8658                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
8659 #endif
8660
8661                                 if (cfg->compile_aot) {
8662                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
8663                                 } else {
8664                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
8665                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
8666                                         ins->inst_p0 = table;
8667                                         ins->dreg = table_reg;
8668                                         MONO_ADD_INS (cfg->cbb, ins);
8669                                 }
8670
8671                                 /* FIXME: Use load_memindex */
8672                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
8673                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
8674                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
8675                         }
8676                         start_new_bblock = 1;
8677                         inline_costs += (BRANCH_COST * 2);
8678                         break;
8679                 }
8680                 case CEE_LDIND_I1:
8681                 case CEE_LDIND_U1:
8682                 case CEE_LDIND_I2:
8683                 case CEE_LDIND_U2:
8684                 case CEE_LDIND_I4:
8685                 case CEE_LDIND_U4:
8686                 case CEE_LDIND_I8:
8687                 case CEE_LDIND_I:
8688                 case CEE_LDIND_R4:
8689                 case CEE_LDIND_R8:
8690                 case CEE_LDIND_REF:
8691                         CHECK_STACK (1);
8692                         --sp;
8693
8694                         switch (*ip) {
8695                         case CEE_LDIND_R4:
8696                         case CEE_LDIND_R8:
8697                                 dreg = alloc_freg (cfg);
8698                                 break;
8699                         case CEE_LDIND_I8:
8700                                 dreg = alloc_lreg (cfg);
8701                                 break;
8702                         case CEE_LDIND_REF:
8703                                 dreg = alloc_ireg_ref (cfg);
8704                                 break;
8705                         default:
8706                                 dreg = alloc_preg (cfg);
8707                         }
8708
8709                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
8710                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
8711                         ins->flags |= ins_flag;
8712                         ins_flag = 0;
8713                         MONO_ADD_INS (bblock, ins);
8714                         *sp++ = ins;
8715                         if (ins->flags & MONO_INST_VOLATILE) {
8716                                 /* Volatile loads have acquire semantics, see 12.6.7 in Ecma 335 */
8717                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8718                                 emit_memory_barrier (cfg, FullBarrier);
8719                         }
8720                         ++ip;
8721                         break;
8722                 case CEE_STIND_REF:
8723                 case CEE_STIND_I1:
8724                 case CEE_STIND_I2:
8725                 case CEE_STIND_I4:
8726                 case CEE_STIND_I8:
8727                 case CEE_STIND_R4:
8728                 case CEE_STIND_R8:
8729                 case CEE_STIND_I:
8730                         CHECK_STACK (2);
8731                         sp -= 2;
8732
8733                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
8734                         ins->flags |= ins_flag;
8735                         ins_flag = 0;
8736
8737                         if (ins->flags & MONO_INST_VOLATILE) {
8738                                 /* Volatile stores have release semantics, see 12.6.7 in Ecma 335 */
8739                                 /* FIXME it's questionable if acquire semantics require full barrier or just LoadLoad*/
8740                                 emit_memory_barrier (cfg, FullBarrier);
8741                         }
8742
8743                         MONO_ADD_INS (bblock, ins);
8744
8745                         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)))
8746                                 emit_write_barrier (cfg, sp [0], sp [1]);
8747
8748                         inline_costs += 1;
8749                         ++ip;
8750                         break;
8751
8752                 case CEE_MUL:
8753                         CHECK_STACK (2);
8754
8755                         MONO_INST_NEW (cfg, ins, (*ip));
8756                         sp -= 2;
8757                         ins->sreg1 = sp [0]->dreg;
8758                         ins->sreg2 = sp [1]->dreg;
8759                         type_from_op (ins, sp [0], sp [1]);
8760                         CHECK_TYPE (ins);
8761                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
8762
8763                         /* Use the immediate opcodes if possible */
8764                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
8765                                 int imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
8766                                 if (imm_opcode != -1) {
8767                                         ins->opcode = imm_opcode;
8768                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
8769                                         ins->sreg2 = -1;
8770
8771                                         sp [1]->opcode = OP_NOP;
8772                                 }
8773                         }
8774
8775                         MONO_ADD_INS ((cfg)->cbb, (ins));
8776
8777                         *sp++ = mono_decompose_opcode (cfg, ins);
8778                         ip++;
8779                         break;
8780                 case CEE_ADD:
8781                 case CEE_SUB:
8782                 case CEE_DIV:
8783                 case CEE_DIV_UN:
8784                 case CEE_REM:
8785                 case CEE_REM_UN:
8786                 case CEE_AND:
8787                 case CEE_OR:
8788                 case CEE_XOR:
8789                 case CEE_SHL:
8790                 case CEE_SHR:
8791                 case CEE_SHR_UN:
8792                         CHECK_STACK (2);
8793
8794                         MONO_INST_NEW (cfg, ins, (*ip));
8795                         sp -= 2;
8796                         ins->sreg1 = sp [0]->dreg;
8797                         ins->sreg2 = sp [1]->dreg;
8798                         type_from_op (ins, sp [0], sp [1]);
8799                         CHECK_TYPE (ins);
8800                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
8801                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
8802
8803                         /* FIXME: Pass opcode to is_inst_imm */
8804
8805                         /* Use the immediate opcodes if possible */
8806                         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)) {
8807                                 int imm_opcode;
8808
8809                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
8810 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
8811                                 /* Keep emulated opcodes which are optimized away later */
8812                                 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) {
8813                                         imm_opcode = mono_op_to_op_imm (ins->opcode);
8814                                 }
8815 #endif
8816                                 if (imm_opcode != -1) {
8817                                         ins->opcode = imm_opcode;
8818                                         if (sp [1]->opcode == OP_I8CONST) {
8819 #if SIZEOF_REGISTER == 8
8820                                                 ins->inst_imm = sp [1]->inst_l;
8821 #else
8822                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
8823                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
8824 #endif
8825                                         }
8826                                         else
8827                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
8828                                         ins->sreg2 = -1;
8829
8830                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
8831                                         if (sp [1]->next == NULL)
8832                                                 sp [1]->opcode = OP_NOP;
8833                                 }
8834                         }
8835                         MONO_ADD_INS ((cfg)->cbb, (ins));
8836
8837                         *sp++ = mono_decompose_opcode (cfg, ins);
8838                         ip++;
8839                         break;
8840                 case CEE_NEG:
8841                 case CEE_NOT:
8842                 case CEE_CONV_I1:
8843                 case CEE_CONV_I2:
8844                 case CEE_CONV_I4:
8845                 case CEE_CONV_R4:
8846                 case CEE_CONV_R8:
8847                 case CEE_CONV_U4:
8848                 case CEE_CONV_I8:
8849                 case CEE_CONV_U8:
8850                 case CEE_CONV_OVF_I8:
8851                 case CEE_CONV_OVF_U8:
8852                 case CEE_CONV_R_UN:
8853                         CHECK_STACK (1);
8854
8855                         /* Special case this earlier so we have long constants in the IR */
8856                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
8857                                 int data = sp [-1]->inst_c0;
8858                                 sp [-1]->opcode = OP_I8CONST;
8859                                 sp [-1]->type = STACK_I8;
8860 #if SIZEOF_REGISTER == 8
8861                                 if ((*ip) == CEE_CONV_U8)
8862                                         sp [-1]->inst_c0 = (guint32)data;
8863                                 else
8864                                         sp [-1]->inst_c0 = data;
8865 #else
8866                                 sp [-1]->inst_ls_word = data;
8867                                 if ((*ip) == CEE_CONV_U8)
8868                                         sp [-1]->inst_ms_word = 0;
8869                                 else
8870                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
8871 #endif
8872                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
8873                         }
8874                         else {
8875                                 ADD_UNOP (*ip);
8876                         }
8877                         ip++;
8878                         break;
8879                 case CEE_CONV_OVF_I4:
8880                 case CEE_CONV_OVF_I1:
8881                 case CEE_CONV_OVF_I2:
8882                 case CEE_CONV_OVF_I:
8883                 case CEE_CONV_OVF_U:
8884                         CHECK_STACK (1);
8885
8886                         if (sp [-1]->type == STACK_R8) {
8887                                 ADD_UNOP (CEE_CONV_OVF_I8);
8888                                 ADD_UNOP (*ip);
8889                         } else {
8890                                 ADD_UNOP (*ip);
8891                         }
8892                         ip++;
8893                         break;
8894                 case CEE_CONV_OVF_U1:
8895                 case CEE_CONV_OVF_U2:
8896                 case CEE_CONV_OVF_U4:
8897                         CHECK_STACK (1);
8898
8899                         if (sp [-1]->type == STACK_R8) {
8900                                 ADD_UNOP (CEE_CONV_OVF_U8);
8901                                 ADD_UNOP (*ip);
8902                         } else {
8903                                 ADD_UNOP (*ip);
8904                         }
8905                         ip++;
8906                         break;
8907                 case CEE_CONV_OVF_I1_UN:
8908                 case CEE_CONV_OVF_I2_UN:
8909                 case CEE_CONV_OVF_I4_UN:
8910                 case CEE_CONV_OVF_I8_UN:
8911                 case CEE_CONV_OVF_U1_UN:
8912                 case CEE_CONV_OVF_U2_UN:
8913                 case CEE_CONV_OVF_U4_UN:
8914                 case CEE_CONV_OVF_U8_UN:
8915                 case CEE_CONV_OVF_I_UN:
8916                 case CEE_CONV_OVF_U_UN:
8917                 case CEE_CONV_U2:
8918                 case CEE_CONV_U1:
8919                 case CEE_CONV_I:
8920                 case CEE_CONV_U:
8921                         CHECK_STACK (1);
8922                         ADD_UNOP (*ip);
8923                         CHECK_CFG_EXCEPTION;
8924                         ip++;
8925                         break;
8926                 case CEE_ADD_OVF:
8927                 case CEE_ADD_OVF_UN:
8928                 case CEE_MUL_OVF:
8929                 case CEE_MUL_OVF_UN:
8930                 case CEE_SUB_OVF:
8931                 case CEE_SUB_OVF_UN:
8932                         CHECK_STACK (2);
8933                         ADD_BINOP (*ip);
8934                         ip++;
8935                         break;
8936                 case CEE_CPOBJ:
8937                         GSHAREDVT_FAILURE (*ip);
8938                         CHECK_OPSIZE (5);
8939                         CHECK_STACK (2);
8940                         token = read32 (ip + 1);
8941                         klass = mini_get_class (method, token, generic_context);
8942                         CHECK_TYPELOAD (klass);
8943                         sp -= 2;
8944                         if (generic_class_is_reference_type (cfg, klass)) {
8945                                 MonoInst *store, *load;
8946                                 int dreg = alloc_ireg_ref (cfg);
8947
8948                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
8949                                 load->flags |= ins_flag;
8950                                 MONO_ADD_INS (cfg->cbb, load);
8951
8952                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
8953                                 store->flags |= ins_flag;
8954                                 MONO_ADD_INS (cfg->cbb, store);
8955
8956                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
8957                                         emit_write_barrier (cfg, sp [0], sp [1]);
8958                         } else {
8959                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
8960                         }
8961                         ins_flag = 0;
8962                         ip += 5;
8963                         break;
8964                 case CEE_LDOBJ: {
8965                         int loc_index = -1;
8966                         int stloc_len = 0;
8967
8968                         CHECK_OPSIZE (5);
8969                         CHECK_STACK (1);
8970                         --sp;
8971                         token = read32 (ip + 1);
8972                         klass = mini_get_class (method, token, generic_context);
8973                         CHECK_TYPELOAD (klass);
8974
8975                         /* Optimize the common ldobj+stloc combination */
8976                         switch (ip [5]) {
8977                         case CEE_STLOC_S:
8978                                 loc_index = ip [6];
8979                                 stloc_len = 2;
8980                                 break;
8981                         case CEE_STLOC_0:
8982                         case CEE_STLOC_1:
8983                         case CEE_STLOC_2:
8984                         case CEE_STLOC_3:
8985                                 loc_index = ip [5] - CEE_STLOC_0;
8986                                 stloc_len = 1;
8987                                 break;
8988                         default:
8989                                 break;
8990                         }
8991
8992                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
8993                                 CHECK_LOCAL (loc_index);
8994
8995                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
8996                                 ins->dreg = cfg->locals [loc_index]->dreg;
8997                                 ip += 5;
8998                                 ip += stloc_len;
8999                                 break;
9000                         }
9001
9002                         /* Optimize the ldobj+stobj combination */
9003                         /* The reference case ends up being a load+store anyway */
9004                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
9005                                 CHECK_STACK (1);
9006
9007                                 sp --;
9008
9009                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
9010
9011                                 ip += 5 + 5;
9012                                 ins_flag = 0;
9013                                 break;
9014                         }
9015
9016                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9017                         *sp++ = ins;
9018
9019                         ip += 5;
9020                         ins_flag = 0;
9021                         inline_costs += 1;
9022                         break;
9023                 }
9024                 case CEE_LDSTR:
9025                         CHECK_STACK_OVF (1);
9026                         CHECK_OPSIZE (5);
9027                         n = read32 (ip + 1);
9028
9029                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
9030                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
9031                                 ins->type = STACK_OBJ;
9032                                 *sp = ins;
9033                         }
9034                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
9035                                 MonoInst *iargs [1];
9036
9037                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
9038                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
9039                         } else {
9040                                 if (cfg->opt & MONO_OPT_SHARED) {
9041                                         MonoInst *iargs [3];
9042
9043                                         if (cfg->compile_aot) {
9044                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
9045                                         }
9046                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
9047                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
9048                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
9049                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
9050                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9051                                 } else {
9052                                         if (bblock->out_of_line) {
9053                                                 MonoInst *iargs [2];
9054
9055                                                 if (image == mono_defaults.corlib) {
9056                                                         /* 
9057                                                          * Avoid relocations in AOT and save some space by using a 
9058                                                          * version of helper_ldstr specialized to mscorlib.
9059                                                          */
9060                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
9061                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
9062                                                 } else {
9063                                                         /* Avoid creating the string object */
9064                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9065                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
9066                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
9067                                                 }
9068                                         } 
9069                                         else
9070                                         if (cfg->compile_aot) {
9071                                                 NEW_LDSTRCONST (cfg, ins, image, n);
9072                                                 *sp = ins;
9073                                                 MONO_ADD_INS (bblock, ins);
9074                                         } 
9075                                         else {
9076                                                 NEW_PCONST (cfg, ins, NULL);
9077                                                 ins->type = STACK_OBJ;
9078                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
9079                                                 if (!ins->inst_p0)
9080                                                         OUT_OF_MEMORY_FAILURE;
9081
9082                                                 *sp = ins;
9083                                                 MONO_ADD_INS (bblock, ins);
9084                                         }
9085                                 }
9086                         }
9087
9088                         sp++;
9089                         ip += 5;
9090                         break;
9091                 case CEE_NEWOBJ: {
9092                         MonoInst *iargs [2];
9093                         MonoMethodSignature *fsig;
9094                         MonoInst this_ins;
9095                         MonoInst *alloc;
9096                         MonoInst *vtable_arg = NULL;
9097
9098                         CHECK_OPSIZE (5);
9099                         token = read32 (ip + 1);
9100                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
9101                         if (!cmethod || mono_loader_get_last_error ())
9102                                 LOAD_ERROR;
9103                         fsig = mono_method_get_signature (cmethod, image, token);
9104                         if (!fsig)
9105                                 LOAD_ERROR;
9106
9107                         mono_save_token_info (cfg, image, token, cmethod);
9108
9109                         if (!mono_class_init (cmethod->klass))
9110                                 TYPE_LOAD_ERROR (cmethod->klass);
9111
9112                         context_used = mini_method_check_context_used (cfg, cmethod);
9113
9114                         if (mono_security_cas_enabled ()) {
9115                                 if (check_linkdemand (cfg, method, cmethod))
9116                                         INLINE_FAILURE ("linkdemand");
9117                                 CHECK_CFG_EXCEPTION;
9118                         } else if (mono_security_core_clr_enabled ()) {
9119                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9120                         }
9121
9122                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
9123                                 emit_generic_class_init (cfg, cmethod->klass);
9124                                 CHECK_TYPELOAD (cmethod->klass);
9125                         }
9126
9127                         /*
9128                         if (cfg->gsharedvt) {
9129                                 if (mini_is_gsharedvt_variable_signature (sig))
9130                                         GSHAREDVT_FAILURE (*ip);
9131                         }
9132                         */
9133
9134                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
9135                                         mono_method_is_generic_sharable (cmethod, TRUE)) {
9136                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
9137                                         mono_class_vtable (cfg->domain, cmethod->klass);
9138                                         CHECK_TYPELOAD (cmethod->klass);
9139
9140                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
9141                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
9142                                 } else {
9143                                         if (context_used) {
9144                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
9145                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
9146                                         } else {
9147                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9148
9149                                                 CHECK_TYPELOAD (cmethod->klass);
9150                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
9151                                         }
9152                                 }
9153                         }
9154
9155                         n = fsig->param_count;
9156                         CHECK_STACK (n);
9157
9158                         /* 
9159                          * Generate smaller code for the common newobj <exception> instruction in
9160                          * argument checking code.
9161                          */
9162                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
9163                                 is_exception_class (cmethod->klass) && n <= 2 &&
9164                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
9165                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
9166                                 MonoInst *iargs [3];
9167
9168                                 g_assert (!vtable_arg);
9169
9170                                 sp -= n;
9171
9172                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
9173                                 switch (n) {
9174                                 case 0:
9175                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
9176                                         break;
9177                                 case 1:
9178                                         iargs [1] = sp [0];
9179                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
9180                                         break;
9181                                 case 2:
9182                                         iargs [1] = sp [0];
9183                                         iargs [2] = sp [1];
9184                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
9185                                         break;
9186                                 default:
9187                                         g_assert_not_reached ();
9188                                 }
9189
9190                                 ip += 5;
9191                                 inline_costs += 5;
9192                                 break;
9193                         }
9194
9195                         /* move the args to allow room for 'this' in the first position */
9196                         while (n--) {
9197                                 --sp;
9198                                 sp [1] = sp [0];
9199                         }
9200
9201                         /* check_call_signature () requires sp[0] to be set */
9202                         this_ins.type = STACK_OBJ;
9203                         sp [0] = &this_ins;
9204                         if (check_call_signature (cfg, fsig, sp))
9205                                 UNVERIFIED;
9206
9207                         iargs [0] = NULL;
9208
9209                         if (mini_class_is_system_array (cmethod->klass)) {
9210                                 g_assert (!vtable_arg);
9211
9212                                 *sp = emit_get_rgctx_method (cfg, context_used,
9213                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
9214
9215                                 /* Avoid varargs in the common case */
9216                                 if (fsig->param_count == 1)
9217                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
9218                                 else if (fsig->param_count == 2)
9219                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
9220                                 else if (fsig->param_count == 3)
9221                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
9222                                 else if (fsig->param_count == 4)
9223                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_4, sp);
9224                                 else
9225                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
9226                         } else if (cmethod->string_ctor) {
9227                                 g_assert (!context_used);
9228                                 g_assert (!vtable_arg);
9229                                 /* we simply pass a null pointer */
9230                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
9231                                 /* now call the string ctor */
9232                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, NULL, NULL, NULL);
9233                         } else {
9234                                 MonoInst* callvirt_this_arg = NULL;
9235                                 
9236                                 if (cmethod->klass->valuetype) {
9237                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
9238                                         MONO_EMIT_NEW_VZERO (cfg, iargs [0]->dreg, cmethod->klass);
9239                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
9240
9241                                         alloc = NULL;
9242
9243                                         /* 
9244                                          * The code generated by mini_emit_virtual_call () expects
9245                                          * iargs [0] to be a boxed instance, but luckily the vcall
9246                                          * will be transformed into a normal call there.
9247                                          */
9248                                 } else if (context_used) {
9249                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
9250                                         *sp = alloc;
9251                                 } else {
9252                                         MonoVTable *vtable = NULL;
9253
9254                                         if (!cfg->compile_aot)
9255                                                 vtable = mono_class_vtable (cfg->domain, cmethod->klass);
9256                                         CHECK_TYPELOAD (cmethod->klass);
9257
9258                                         /*
9259                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
9260                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
9261                                          * As a workaround, we call class cctors before allocating objects.
9262                                          */
9263                                         if (mini_field_access_needs_cctor_run (cfg, method, cmethod->klass, vtable) && !(g_slist_find (class_inits, cmethod->klass))) {
9264                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, cmethod->klass, helper_sig_class_init_trampoline, NULL);
9265                                                 if (cfg->verbose_level > 2)
9266                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
9267                                                 class_inits = g_slist_prepend (class_inits, cmethod->klass);
9268                                         }
9269
9270                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
9271                                         *sp = alloc;
9272                                 }
9273                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
9274
9275                                 if (alloc)
9276                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
9277
9278                                 /* Now call the actual ctor */
9279                                 /* Avoid virtual calls to ctors if possible */
9280                                 if (mono_class_is_marshalbyref (cmethod->klass))
9281                                         callvirt_this_arg = sp [0];
9282
9283
9284                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
9285                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
9286                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
9287                                                 *sp = ins;
9288                                                 sp++;
9289                                         }
9290
9291                                         CHECK_CFG_EXCEPTION;
9292                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
9293                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
9294                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
9295                                     !g_list_find (dont_inline, cmethod)) {
9296                                         int costs;
9297
9298                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
9299                                                 cfg->real_offset += 5;
9300                                                 bblock = cfg->cbb;
9301
9302                                                 inline_costs += costs - 5;
9303                                         } else {
9304                                                 INLINE_FAILURE ("inline failure");
9305                                                 // FIXME-VT: Clean this up
9306                                                 if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig))
9307                                                         GSHAREDVT_FAILURE(*ip);
9308                                                 mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp, callvirt_this_arg, NULL, NULL);
9309                                         }
9310                                 } else if (cfg->gsharedvt && mini_is_gsharedvt_signature (cfg, fsig)) {
9311                                         MonoInst *addr;
9312
9313                                         addr = emit_get_rgctx_gsharedvt_call (cfg, context_used, fsig, cmethod, MONO_RGCTX_INFO_METHOD_GSHAREDVT_OUT_TRAMPOLINE);
9314                                         mono_emit_calli (cfg, fsig, sp, addr, NULL, vtable_arg);
9315                                 } else if (context_used &&
9316                                                 (!mono_method_is_generic_sharable (cmethod, TRUE) ||
9317                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
9318                                         MonoInst *cmethod_addr;
9319
9320                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
9321                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
9322
9323                                         mono_emit_calli (cfg, fsig, sp, cmethod_addr, NULL, vtable_arg);
9324                                 } else {
9325                                         INLINE_FAILURE ("ctor call");
9326                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, FALSE, sp,
9327                                                                                                           callvirt_this_arg, NULL, vtable_arg);
9328                                 }
9329                         }
9330
9331                         if (alloc == NULL) {
9332                                 /* Valuetype */
9333                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
9334                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
9335                                 *sp++= ins;
9336                         }
9337                         else
9338                                 *sp++ = alloc;
9339                         
9340                         ip += 5;
9341                         inline_costs += 5;
9342                         break;
9343                 }
9344                 case CEE_CASTCLASS:
9345                         CHECK_STACK (1);
9346                         --sp;
9347                         CHECK_OPSIZE (5);
9348                         token = read32 (ip + 1);
9349                         klass = mini_get_class (method, token, generic_context);
9350                         CHECK_TYPELOAD (klass);
9351                         if (sp [0]->type != STACK_OBJ)
9352                                 UNVERIFIED;
9353
9354                         context_used = mini_class_check_context_used (cfg, klass);
9355
9356                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9357                                 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
9358                                 MonoInst *args [3];
9359
9360                                 /* obj */
9361                                 args [0] = *sp;
9362
9363                                 /* klass */
9364                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9365
9366                                 /* inline cache*/
9367                                 if (cfg->compile_aot)
9368                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9369                                 else
9370                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9371
9372                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9373
9374                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9375                                 *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
9376                                 reset_cast_details (cfg);
9377                                 ip += 5;
9378                                 inline_costs += 2;
9379                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9380                                 MonoMethod *mono_castclass;
9381                                 MonoInst *iargs [1];
9382                                 int costs;
9383
9384                                 mono_castclass = mono_marshal_get_castclass (klass); 
9385                                 iargs [0] = sp [0];
9386                                 
9387                                 save_cast_details (cfg, klass, sp [0]->dreg, TRUE, &bblock);
9388                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9389                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9390                                 reset_cast_details (cfg);
9391                                 CHECK_CFG_EXCEPTION;
9392                                 g_assert (costs > 0);
9393                                 
9394                                 ip += 5;
9395                                 cfg->real_offset += 5;
9396                                 bblock = cfg->cbb;
9397
9398                                 *sp++ = iargs [0];
9399
9400                                 inline_costs += costs;
9401                         }
9402                         else {
9403                                 ins = handle_castclass (cfg, klass, *sp, context_used);
9404                                 CHECK_CFG_EXCEPTION;
9405                                 bblock = cfg->cbb;
9406                                 *sp ++ = ins;
9407                                 ip += 5;
9408                         }
9409                         break;
9410                 case CEE_ISINST: {
9411                         CHECK_STACK (1);
9412                         --sp;
9413                         CHECK_OPSIZE (5);
9414                         token = read32 (ip + 1);
9415                         klass = mini_get_class (method, token, generic_context);
9416                         CHECK_TYPELOAD (klass);
9417                         if (sp [0]->type != STACK_OBJ)
9418                                 UNVERIFIED;
9419  
9420                         context_used = mini_class_check_context_used (cfg, klass);
9421
9422                         if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9423                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
9424                                 MonoInst *args [3];
9425
9426                                 /* obj */
9427                                 args [0] = *sp;
9428
9429                                 /* klass */
9430                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9431
9432                                 /* inline cache*/
9433                                 if (cfg->compile_aot)
9434                                         EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9435                                 else
9436                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9437
9438                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
9439                                 ip += 5;
9440                                 inline_costs += 2;
9441                         } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9442                                 MonoMethod *mono_isinst;
9443                                 MonoInst *iargs [1];
9444                                 int costs;
9445
9446                                 mono_isinst = mono_marshal_get_isinst (klass); 
9447                                 iargs [0] = sp [0];
9448
9449                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
9450                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
9451                                 CHECK_CFG_EXCEPTION;
9452                                 g_assert (costs > 0);
9453                                 
9454                                 ip += 5;
9455                                 cfg->real_offset += 5;
9456                                 bblock = cfg->cbb;
9457
9458                                 *sp++= iargs [0];
9459
9460                                 inline_costs += costs;
9461                         }
9462                         else {
9463                                 ins = handle_isinst (cfg, klass, *sp, context_used);
9464                                 CHECK_CFG_EXCEPTION;
9465                                 bblock = cfg->cbb;
9466                                 *sp ++ = ins;
9467                                 ip += 5;
9468                         }
9469                         break;
9470                 }
9471                 case CEE_UNBOX_ANY: {
9472                         CHECK_STACK (1);
9473                         --sp;
9474                         CHECK_OPSIZE (5);
9475                         token = read32 (ip + 1);
9476                         klass = mini_get_class (method, token, generic_context);
9477                         CHECK_TYPELOAD (klass);
9478  
9479                         mono_save_token_info (cfg, image, token, klass);
9480
9481                         context_used = mini_class_check_context_used (cfg, klass);
9482
9483                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9484                                 *sp = handle_unbox_gsharedvt (cfg, klass, *sp, &bblock);
9485                                 sp ++;
9486
9487                                 ip += 5;
9488                                 inline_costs += 2;
9489                                 break;
9490                         }
9491
9492                         if (generic_class_is_reference_type (cfg, klass)) {
9493                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
9494                                 if (!context_used && mini_class_has_reference_variant_generic_argument (cfg, klass, context_used)) {
9495                                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
9496                                         MonoInst *args [3];
9497
9498                                         /* obj */
9499                                         args [0] = *sp;
9500
9501                                         /* klass */
9502                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
9503
9504                                         /* inline cache*/
9505                                         /*FIXME AOT support*/
9506                                         if (cfg->compile_aot)
9507                                                 EMIT_NEW_AOTCONST (cfg, args [2], MONO_PATCH_INFO_CASTCLASS_CACHE, NULL);
9508                                         else
9509                                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
9510
9511                                         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
9512                                         *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
9513                                         ip += 5;
9514                                         inline_costs += 2;
9515                                 } else if (!context_used && (mono_class_is_marshalbyref (klass) || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
9516                                         MonoMethod *mono_castclass;
9517                                         MonoInst *iargs [1];
9518                                         int costs;
9519
9520                                         mono_castclass = mono_marshal_get_castclass (klass); 
9521                                         iargs [0] = sp [0];
9522
9523                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
9524                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9525                                         CHECK_CFG_EXCEPTION;
9526                                         g_assert (costs > 0);
9527                                 
9528                                         ip += 5;
9529                                         cfg->real_offset += 5;
9530                                         bblock = cfg->cbb;
9531
9532                                         *sp++ = iargs [0];
9533                                         inline_costs += costs;
9534                                 } else {
9535                                         ins = handle_castclass (cfg, klass, *sp, context_used);
9536                                         CHECK_CFG_EXCEPTION;
9537                                         bblock = cfg->cbb;
9538                                         *sp ++ = ins;
9539                                         ip += 5;
9540                                 }
9541                                 break;
9542                         }
9543
9544                         if (mono_class_is_nullable (klass)) {
9545                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
9546                                 *sp++= ins;
9547                                 ip += 5;
9548                                 break;
9549                         }
9550
9551                         /* UNBOX */
9552                         ins = handle_unbox (cfg, klass, sp, context_used);
9553                         *sp = ins;
9554
9555                         ip += 5;
9556
9557                         /* LDOBJ */
9558                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
9559                         *sp++ = ins;
9560
9561                         inline_costs += 2;
9562                         break;
9563                 }
9564                 case CEE_BOX: {
9565                         MonoInst *val;
9566
9567                         CHECK_STACK (1);
9568                         --sp;
9569                         val = *sp;
9570                         CHECK_OPSIZE (5);
9571                         token = read32 (ip + 1);
9572                         klass = mini_get_class (method, token, generic_context);
9573                         CHECK_TYPELOAD (klass);
9574
9575                         mono_save_token_info (cfg, image, token, klass);
9576
9577                         context_used = mini_class_check_context_used (cfg, klass);
9578
9579                         if (generic_class_is_reference_type (cfg, klass)) {
9580                                 *sp++ = val;
9581                                 ip += 5;
9582                                 break;
9583                         }
9584
9585                         if (klass == mono_defaults.void_class)
9586                                 UNVERIFIED;
9587                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
9588                                 UNVERIFIED;
9589                         /* frequent check in generic code: box (struct), brtrue */
9590
9591                         // FIXME: LLVM can't handle the inconsistent bb linking
9592                         if (!mono_class_is_nullable (klass) &&
9593                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
9594                                 (ip [5] == CEE_BRTRUE || 
9595                                  ip [5] == CEE_BRTRUE_S ||
9596                                  ip [5] == CEE_BRFALSE ||
9597                                  ip [5] == CEE_BRFALSE_S)) {
9598                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
9599                                 int dreg;
9600                                 MonoBasicBlock *true_bb, *false_bb;
9601
9602                                 ip += 5;
9603
9604                                 if (cfg->verbose_level > 3) {
9605                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9606                                         printf ("<box+brtrue opt>\n");
9607                                 }
9608
9609                                 switch (*ip) {
9610                                 case CEE_BRTRUE_S:
9611                                 case CEE_BRFALSE_S:
9612                                         CHECK_OPSIZE (2);
9613                                         ip++;
9614                                         target = ip + 1 + (signed char)(*ip);
9615                                         ip++;
9616                                         break;
9617                                 case CEE_BRTRUE:
9618                                 case CEE_BRFALSE:
9619                                         CHECK_OPSIZE (5);
9620                                         ip++;
9621                                         target = ip + 4 + (gint)(read32 (ip));
9622                                         ip += 4;
9623                                         break;
9624                                 default:
9625                                         g_assert_not_reached ();
9626                                 }
9627
9628                                 /* 
9629                                  * We need to link both bblocks, since it is needed for handling stack
9630                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
9631                                  * Branching to only one of them would lead to inconsistencies, so
9632                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
9633                                  */
9634                                 GET_BBLOCK (cfg, true_bb, target);
9635                                 GET_BBLOCK (cfg, false_bb, ip);
9636
9637                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
9638                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
9639
9640                                 if (sp != stack_start) {
9641                                         handle_stack_args (cfg, stack_start, sp - stack_start);
9642                                         sp = stack_start;
9643                                         CHECK_UNVERIFIABLE (cfg);
9644                                 }
9645
9646                                 if (COMPILE_LLVM (cfg)) {
9647                                         dreg = alloc_ireg (cfg);
9648                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
9649                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
9650
9651                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
9652                                 } else {
9653                                         /* The JIT can't eliminate the iconst+compare */
9654                                         MONO_INST_NEW (cfg, ins, OP_BR);
9655                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
9656                                         MONO_ADD_INS (cfg->cbb, ins);
9657                                 }
9658
9659                                 start_new_bblock = 1;
9660                                 break;
9661                         }
9662
9663                         *sp++ = handle_box (cfg, val, klass, context_used, &bblock);
9664
9665                         CHECK_CFG_EXCEPTION;
9666                         ip += 5;
9667                         inline_costs += 1;
9668                         break;
9669                 }
9670                 case CEE_UNBOX: {
9671                         CHECK_STACK (1);
9672                         --sp;
9673                         CHECK_OPSIZE (5);
9674                         token = read32 (ip + 1);
9675                         klass = mini_get_class (method, token, generic_context);
9676                         CHECK_TYPELOAD (klass);
9677
9678                         mono_save_token_info (cfg, image, token, klass);
9679
9680                         context_used = mini_class_check_context_used (cfg, klass);
9681
9682                         if (mono_class_is_nullable (klass)) {
9683                                 MonoInst *val;
9684
9685                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
9686                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
9687
9688                                 *sp++= ins;
9689                         } else {
9690                                 ins = handle_unbox (cfg, klass, sp, context_used);
9691                                 *sp++ = ins;
9692                         }
9693                         ip += 5;
9694                         inline_costs += 2;
9695                         break;
9696                 }
9697                 case CEE_LDFLD:
9698                 case CEE_LDFLDA:
9699                 case CEE_STFLD:
9700                 case CEE_LDSFLD:
9701                 case CEE_LDSFLDA:
9702                 case CEE_STSFLD: {
9703                         MonoClassField *field;
9704 #ifndef DISABLE_REMOTING
9705                         int costs;
9706 #endif
9707                         guint foffset;
9708                         gboolean is_instance;
9709                         int op;
9710                         gpointer addr = NULL;
9711                         gboolean is_special_static;
9712                         MonoType *ftype;
9713                         MonoInst *store_val = NULL;
9714
9715                         op = *ip;
9716                         is_instance = (op == CEE_LDFLD || op == CEE_LDFLDA || op == CEE_STFLD);
9717                         if (is_instance) {
9718                                 if (op == CEE_STFLD) {
9719                                         CHECK_STACK (2);
9720                                         sp -= 2;
9721                                         store_val = sp [1];
9722                                 } else {
9723                                         CHECK_STACK (1);
9724                                         --sp;
9725                                 }
9726                                 if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
9727                                         UNVERIFIED;
9728                                 if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
9729                                         UNVERIFIED;
9730                         } else {
9731                                 if (op == CEE_STSFLD) {
9732                                         CHECK_STACK (1);
9733                                         sp--;
9734                                         store_val = sp [0];
9735                                 }
9736                         }
9737
9738                         CHECK_OPSIZE (5);
9739                         token = read32 (ip + 1);
9740                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
9741                                 field = mono_method_get_wrapper_data (method, token);
9742                                 klass = field->parent;
9743                         }
9744                         else {
9745                                 field = mono_field_from_token (image, token, &klass, generic_context);
9746                         }
9747                         if (!field)
9748                                 LOAD_ERROR;
9749                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
9750                                 FIELD_ACCESS_FAILURE;
9751                         mono_class_init (klass);
9752
9753                         if (is_instance && *ip != CEE_LDFLDA && is_magic_tls_access (field))
9754                                 UNVERIFIED;
9755
9756                         /* if the class is Critical then transparent code cannot access it's fields */
9757                         if (!is_instance && mono_security_core_clr_enabled ())
9758                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
9759
9760                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
9761                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
9762                         if (mono_security_core_clr_enabled ())
9763                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
9764                         */
9765
9766                         /*
9767                          * LDFLD etc. is usable on static fields as well, so convert those cases to
9768                          * the static case.
9769                          */
9770                         if (is_instance && field->type->attrs & FIELD_ATTRIBUTE_STATIC) {
9771                                 switch (op) {
9772                                 case CEE_LDFLD:
9773                                         op = CEE_LDSFLD;
9774                                         break;
9775                                 case CEE_STFLD:
9776                                         op = CEE_STSFLD;
9777                                         break;
9778                                 case CEE_LDFLDA:
9779                                         op = CEE_LDSFLDA;
9780                                         break;
9781                                 default:
9782                                         g_assert_not_reached ();
9783                                 }
9784                                 is_instance = FALSE;
9785                         }
9786
9787                         context_used = mini_class_check_context_used (cfg, klass);
9788
9789                         /* INSTANCE CASE */
9790
9791                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
9792                         if (op == CEE_STFLD) {
9793                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
9794                                         UNVERIFIED;
9795 #ifndef DISABLE_REMOTING
9796                                 if ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class) {
9797                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
9798                                         MonoInst *iargs [5];
9799
9800                                         GSHAREDVT_FAILURE (op);
9801
9802                                         iargs [0] = sp [0];
9803                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
9804                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
9805                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
9806                                                     field->offset);
9807                                         iargs [4] = sp [1];
9808
9809                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
9810                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
9811                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
9812                                                 CHECK_CFG_EXCEPTION;
9813                                                 g_assert (costs > 0);
9814                                                       
9815                                                 cfg->real_offset += 5;
9816                                                 bblock = cfg->cbb;
9817
9818                                                 inline_costs += costs;
9819                                         } else {
9820                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
9821                                         }
9822                                 } else
9823 #endif
9824                                 {
9825                                         MonoInst *store;
9826
9827                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9828
9829                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9830                                                 MonoInst *offset_ins;
9831
9832                                                 context_used = mini_class_check_context_used (cfg, klass);
9833
9834                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
9835                                                 dreg = alloc_ireg_mp (cfg);
9836                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
9837                                                 /* The decomposition will call mini_emit_stobj () which will emit a wbarrier if needed */
9838                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, dreg, 0, sp [1]->dreg);
9839                                         } else {
9840                                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
9841                                         }
9842                                         if (sp [0]->opcode != OP_LDADDR)
9843                                                 store->flags |= MONO_INST_FAULT;
9844
9845                                 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)) {
9846                                         /* insert call to write barrier */
9847                                         MonoInst *ptr;
9848                                         int dreg;
9849
9850                                         dreg = alloc_ireg_mp (cfg);
9851                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
9852                                         emit_write_barrier (cfg, ptr, sp [1]);
9853                                 }
9854
9855                                         store->flags |= ins_flag;
9856                                 }
9857                                 ins_flag = 0;
9858                                 ip += 5;
9859                                 break;
9860                         }
9861
9862 #ifndef DISABLE_REMOTING
9863                         if (is_instance && ((mono_class_is_marshalbyref (klass) && !MONO_CHECK_THIS (sp [0])) || mono_class_is_contextbound (klass) || klass == mono_defaults.marshalbyrefobject_class)) {
9864                                 MonoMethod *wrapper = (op == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
9865                                 MonoInst *iargs [4];
9866
9867                                 GSHAREDVT_FAILURE (op);
9868
9869                                 iargs [0] = sp [0];
9870                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
9871                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
9872                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
9873                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
9874                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
9875                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
9876                                         CHECK_CFG_EXCEPTION;
9877                                         bblock = cfg->cbb;
9878                                         g_assert (costs > 0);
9879                                                       
9880                                         cfg->real_offset += 5;
9881
9882                                         *sp++ = iargs [0];
9883
9884                                         inline_costs += costs;
9885                                 } else {
9886                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
9887                                         *sp++ = ins;
9888                                 }
9889                         } else 
9890 #endif
9891                         if (is_instance) {
9892                                 if (sp [0]->type == STACK_VTYPE) {
9893                                         MonoInst *var;
9894
9895                                         /* Have to compute the address of the variable */
9896
9897                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
9898                                         if (!var)
9899                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
9900                                         else
9901                                                 g_assert (var->klass == klass);
9902                                         
9903                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
9904                                         sp [0] = ins;
9905                                 }
9906
9907                                 if (op == CEE_LDFLDA) {
9908                                         if (is_magic_tls_access (field)) {
9909                                                 GSHAREDVT_FAILURE (*ip);
9910                                                 ins = sp [0];
9911                                                 *sp++ = create_magic_tls_access (cfg, field, &cached_tls_addr, ins);
9912                                         } else {
9913                                                 if (sp [0]->type == STACK_OBJ) {
9914                                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
9915                                                         MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
9916                                                 }
9917
9918                                                 dreg = alloc_ireg_mp (cfg);
9919
9920                                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
9921                                                         MonoInst *offset_ins;
9922
9923                                                         offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
9924                                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
9925                                                 } else {
9926                                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
9927                                                 }
9928                                                 ins->klass = mono_class_from_mono_type (field->type);
9929                                                 ins->type = STACK_MP;
9930                                                 *sp++ = ins;
9931                                         }
9932                                 } else {
9933                                         MonoInst *load;
9934
9935                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
9936
9937                                         if (mini_is_gsharedvt_klass (cfg, klass)) {
9938                                                 MonoInst *offset_ins;
9939
9940                                                 offset_ins = emit_get_gsharedvt_info (cfg, field, MONO_RGCTX_INFO_FIELD_OFFSET);
9941                                                 dreg = alloc_ireg_mp (cfg);
9942                                                 EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, sp [0]->dreg, offset_ins->dreg);
9943                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, dreg, 0);
9944                                         } else {
9945                                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
9946                                         }
9947                                         load->flags |= ins_flag;
9948                                         if (sp [0]->opcode != OP_LDADDR)
9949                                                 load->flags |= MONO_INST_FAULT;
9950                                         *sp++ = load;
9951                                 }
9952                         }
9953
9954                         if (is_instance) {
9955                                 ins_flag = 0;
9956                                 ip += 5;
9957                                 break;
9958                         }
9959
9960                         /* STATIC CASE */
9961
9962                         /*
9963                          * We can only support shared generic static
9964                          * field access on architectures where the
9965                          * trampoline code has been extended to handle
9966                          * the generic class init.
9967                          */
9968 #ifndef MONO_ARCH_VTABLE_REG
9969                         GENERIC_SHARING_FAILURE (op);
9970 #endif
9971
9972                         context_used = mini_class_check_context_used (cfg, klass);
9973
9974                         ftype = mono_field_get_type (field);
9975
9976                         if (ftype->attrs & FIELD_ATTRIBUTE_LITERAL)
9977                                 UNVERIFIED;
9978
9979                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
9980                          * to be called here.
9981                          */
9982                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
9983                                 mono_class_vtable (cfg->domain, klass);
9984                                 CHECK_TYPELOAD (klass);
9985                         }
9986                         mono_domain_lock (cfg->domain);
9987                         if (cfg->domain->special_static_fields)
9988                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
9989                         mono_domain_unlock (cfg->domain);
9990
9991                         is_special_static = mono_class_field_is_special_static (field);
9992
9993                         /* Generate IR to compute the field address */
9994                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && mono_get_thread_intrinsic (cfg) && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
9995                                 /*
9996                                  * Fast access to TLS data
9997                                  * Inline version of get_thread_static_data () in
9998                                  * threads.c.
9999                                  */
10000                                 guint32 offset;
10001                                 int idx, static_data_reg, array_reg, dreg;
10002                                 MonoInst *thread_ins;
10003
10004                                 GSHAREDVT_FAILURE (op);
10005
10006                                 // offset &= 0x7fffffff;
10007                                 // idx = (offset >> 24) - 1;
10008                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
10009
10010                                 thread_ins = mono_get_thread_intrinsic (cfg);
10011                                 MONO_ADD_INS (cfg->cbb, thread_ins);
10012                                 static_data_reg = alloc_ireg (cfg);
10013                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
10014
10015                                 if (cfg->compile_aot) {
10016                                         int offset_reg, offset2_reg, idx_reg;
10017
10018                                         /* For TLS variables, this will return the TLS offset */
10019                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
10020                                         offset_reg = ins->dreg;
10021                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
10022                                         idx_reg = alloc_ireg (cfg);
10023                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
10024                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
10025                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
10026                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
10027                                         array_reg = alloc_ireg (cfg);
10028                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
10029                                         offset2_reg = alloc_ireg (cfg);
10030                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
10031                                         dreg = alloc_ireg (cfg);
10032                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
10033                                 } else {
10034                                         offset = (gsize)addr & 0x7fffffff;
10035                                         idx = (offset >> 24) - 1;
10036
10037                                         array_reg = alloc_ireg (cfg);
10038                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
10039                                         dreg = alloc_ireg (cfg);
10040                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
10041                                 }
10042                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
10043                                         (cfg->compile_aot && is_special_static) ||
10044                                         (context_used && is_special_static)) {
10045                                 MonoInst *iargs [2];
10046
10047                                 g_assert (field->parent);
10048                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10049                                 if (context_used) {
10050                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
10051                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
10052                                 } else {
10053                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10054                                 }
10055                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10056                         } else if (context_used) {
10057                                 MonoInst *static_data;
10058
10059                                 /*
10060                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
10061                                         method->klass->name_space, method->klass->name, method->name,
10062                                         depth, field->offset);
10063                                 */
10064
10065                                 if (mono_class_needs_cctor_run (klass, method))
10066                                         emit_generic_class_init (cfg, klass);
10067
10068                                 /*
10069                                  * The pointer we're computing here is
10070                                  *
10071                                  *   super_info.static_data + field->offset
10072                                  */
10073                                 static_data = emit_get_rgctx_klass (cfg, context_used,
10074                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
10075
10076                                 if (mini_is_gsharedvt_klass (cfg, klass)) {
10077                                         MonoInst *offset_ins;
10078
10079                                         offset_ins = emit_get_rgctx_field (cfg, context_used, field, MONO_RGCTX_INFO_FIELD_OFFSET);
10080                                         dreg = alloc_ireg_mp (cfg);
10081                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, static_data->dreg, offset_ins->dreg);
10082                                 } else if (field->offset == 0) {
10083                                         ins = static_data;
10084                                 } else {
10085                                         int addr_reg = mono_alloc_preg (cfg);
10086                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
10087                                 }
10088                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
10089                                 MonoInst *iargs [2];
10090
10091                                 g_assert (field->parent);
10092                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10093                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
10094                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
10095                         } else {
10096                                 MonoVTable *vtable = NULL;
10097
10098                                 if (!cfg->compile_aot)
10099                                         vtable = mono_class_vtable (cfg->domain, klass);
10100                                 CHECK_TYPELOAD (klass);
10101
10102                                 if (!addr) {
10103                                         if (mini_field_access_needs_cctor_run (cfg, method, klass, vtable)) {
10104                                                 if (!(g_slist_find (class_inits, klass))) {
10105                                                         mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, klass, helper_sig_class_init_trampoline, NULL);
10106                                                         if (cfg->verbose_level > 2)
10107                                                                 printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
10108                                                         class_inits = g_slist_prepend (class_inits, klass);
10109                                                 }
10110                                         } else {
10111                                                 if (cfg->run_cctors) {
10112                                                         MonoException *ex;
10113                                                         /* This makes so that inline cannot trigger */
10114                                                         /* .cctors: too many apps depend on them */
10115                                                         /* running with a specific order... */
10116                                                         g_assert (vtable);
10117                                                         if (! vtable->initialized)
10118                                                                 INLINE_FAILURE ("class init");
10119                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
10120                                                         if (ex) {
10121                                                                 set_exception_object (cfg, ex);
10122                                                                 goto exception_exit;
10123                                                         }
10124                                                 }
10125                                         }
10126                                         if (cfg->compile_aot)
10127                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
10128                                         else {
10129                                                 g_assert (vtable);
10130                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10131                                                 EMIT_NEW_PCONST (cfg, ins, addr);
10132                                         }
10133                                 } else {
10134                                         MonoInst *iargs [1];
10135                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
10136                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
10137                                 }
10138                         }
10139
10140                         /* Generate IR to do the actual load/store operation */
10141
10142                         if (op == CEE_LDSFLDA) {
10143                                 ins->klass = mono_class_from_mono_type (ftype);
10144                                 ins->type = STACK_PTR;
10145                                 *sp++ = ins;
10146                         } else if (op == CEE_STSFLD) {
10147                                 MonoInst *store;
10148
10149                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, ftype, ins->dreg, 0, store_val->dreg);
10150                                 store->flags |= ins_flag;
10151                         } else {
10152                                 gboolean is_const = FALSE;
10153                                 MonoVTable *vtable = NULL;
10154                                 gpointer addr = NULL;
10155
10156                                 if (!context_used) {
10157                                         vtable = mono_class_vtable (cfg->domain, klass);
10158                                         CHECK_TYPELOAD (klass);
10159                                 }
10160                                 if ((ftype->attrs & FIELD_ATTRIBUTE_INIT_ONLY) && (((addr = mono_aot_readonly_field_override (field)) != NULL) ||
10161                                                 (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && vtable->initialized))) {
10162                                         int ro_type = ftype->type;
10163                                         if (!addr)
10164                                                 addr = (char*)mono_vtable_get_static_field_data (vtable) + field->offset;
10165                                         if (ro_type == MONO_TYPE_VALUETYPE && ftype->data.klass->enumtype) {
10166                                                 ro_type = mono_class_enum_basetype (ftype->data.klass)->type;
10167                                         }
10168
10169                                         GSHAREDVT_FAILURE (op);
10170
10171                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
10172                                         is_const = TRUE;
10173                                         switch (ro_type) {
10174                                         case MONO_TYPE_BOOLEAN:
10175                                         case MONO_TYPE_U1:
10176                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
10177                                                 sp++;
10178                                                 break;
10179                                         case MONO_TYPE_I1:
10180                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
10181                                                 sp++;
10182                                                 break;                                          
10183                                         case MONO_TYPE_CHAR:
10184                                         case MONO_TYPE_U2:
10185                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
10186                                                 sp++;
10187                                                 break;
10188                                         case MONO_TYPE_I2:
10189                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
10190                                                 sp++;
10191                                                 break;
10192                                                 break;
10193                                         case MONO_TYPE_I4:
10194                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
10195                                                 sp++;
10196                                                 break;                                          
10197                                         case MONO_TYPE_U4:
10198                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
10199                                                 sp++;
10200                                                 break;
10201                                         case MONO_TYPE_I:
10202                                         case MONO_TYPE_U:
10203                                         case MONO_TYPE_PTR:
10204                                         case MONO_TYPE_FNPTR:
10205                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10206                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
10207                                                 sp++;
10208                                                 break;
10209                                         case MONO_TYPE_STRING:
10210                                         case MONO_TYPE_OBJECT:
10211                                         case MONO_TYPE_CLASS:
10212                                         case MONO_TYPE_SZARRAY:
10213                                         case MONO_TYPE_ARRAY:
10214                                                 if (!mono_gc_is_moving ()) {
10215                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
10216                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
10217                                                         sp++;
10218                                                 } else {
10219                                                         is_const = FALSE;
10220                                                 }
10221                                                 break;
10222                                         case MONO_TYPE_I8:
10223                                         case MONO_TYPE_U8:
10224                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
10225                                                 sp++;
10226                                                 break;
10227                                         case MONO_TYPE_R4:
10228                                         case MONO_TYPE_R8:
10229                                         case MONO_TYPE_VALUETYPE:
10230                                         default:
10231                                                 is_const = FALSE;
10232                                                 break;
10233                                         }
10234                                 }
10235
10236                                 if (!is_const) {
10237                                         MonoInst *load;
10238
10239                                         CHECK_STACK_OVF (1);
10240
10241                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
10242                                         load->flags |= ins_flag;
10243                                         ins_flag = 0;
10244                                         *sp++ = load;
10245                                 }
10246                         }
10247                         ins_flag = 0;
10248                         ip += 5;
10249                         break;
10250                 }
10251                 case CEE_STOBJ:
10252                         CHECK_STACK (2);
10253                         sp -= 2;
10254                         CHECK_OPSIZE (5);
10255                         token = read32 (ip + 1);
10256                         klass = mini_get_class (method, token, generic_context);
10257                         CHECK_TYPELOAD (klass);
10258                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
10259                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
10260                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
10261                                         generic_class_is_reference_type (cfg, klass)) {
10262                                 /* insert call to write barrier */
10263                                 emit_write_barrier (cfg, sp [0], sp [1]);
10264                         }
10265                         ins_flag = 0;
10266                         ip += 5;
10267                         inline_costs += 1;
10268                         break;
10269
10270                         /*
10271                          * Array opcodes
10272                          */
10273                 case CEE_NEWARR: {
10274                         MonoInst *len_ins;
10275                         const char *data_ptr;
10276                         int data_size = 0;
10277                         guint32 field_token;
10278
10279                         CHECK_STACK (1);
10280                         --sp;
10281
10282                         CHECK_OPSIZE (5);
10283                         token = read32 (ip + 1);
10284
10285                         klass = mini_get_class (method, token, generic_context);
10286                         CHECK_TYPELOAD (klass);
10287
10288                         context_used = mini_class_check_context_used (cfg, klass);
10289
10290                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
10291                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_OVF_U4);
10292                                 ins->sreg1 = sp [0]->dreg;
10293                                 ins->type = STACK_I4;
10294                                 ins->dreg = alloc_ireg (cfg);
10295                                 MONO_ADD_INS (cfg->cbb, ins);
10296                                 *sp = mono_decompose_opcode (cfg, ins);
10297                         }
10298
10299                         if (context_used) {
10300                                 MonoInst *args [3];
10301                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10302                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class);
10303
10304                                 /* FIXME: Use OP_NEWARR and decompose later to help abcrem */
10305
10306                                 /* vtable */
10307                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
10308                                         array_class, MONO_RGCTX_INFO_VTABLE);
10309                                 /* array len */
10310                                 args [1] = sp [0];
10311
10312                                 if (managed_alloc)
10313                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
10314                                 else
10315                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
10316                         } else {
10317                                 if (cfg->opt & MONO_OPT_SHARED) {
10318                                         /* Decompose now to avoid problems with references to the domainvar */
10319                                         MonoInst *iargs [3];
10320
10321                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
10322                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
10323                                         iargs [2] = sp [0];
10324
10325                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
10326                                 } else {
10327                                         /* Decompose later since it is needed by abcrem */
10328                                         MonoClass *array_type = mono_array_class_get (klass, 1);
10329                                         mono_class_vtable (cfg->domain, array_type);
10330                                         CHECK_TYPELOAD (array_type);
10331
10332                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
10333                                         ins->dreg = alloc_ireg_ref (cfg);
10334                                         ins->sreg1 = sp [0]->dreg;
10335                                         ins->inst_newa_class = klass;
10336                                         ins->type = STACK_OBJ;
10337                                         ins->klass = array_type;
10338                                         MONO_ADD_INS (cfg->cbb, ins);
10339                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10340                                         cfg->cbb->has_array_access = TRUE;
10341
10342                                         /* Needed so mono_emit_load_get_addr () gets called */
10343                                         mono_get_got_var (cfg);
10344                                 }
10345                         }
10346
10347                         len_ins = sp [0];
10348                         ip += 5;
10349                         *sp++ = ins;
10350                         inline_costs += 1;
10351
10352                         /* 
10353                          * we inline/optimize the initialization sequence if possible.
10354                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
10355                          * for small sizes open code the memcpy
10356                          * ensure the rva field is big enough
10357                          */
10358                         if ((cfg->opt & MONO_OPT_INTRINS) && ip + 6 < end && ip_in_bb (cfg, bblock, ip + 6) && (len_ins->opcode == OP_ICONST) && (data_ptr = initialize_array_data (method, cfg->compile_aot, ip, klass, len_ins->inst_c0, &data_size, &field_token))) {
10359                                 MonoMethod *memcpy_method = get_memcpy_method ();
10360                                 MonoInst *iargs [3];
10361                                 int add_reg = alloc_ireg_mp (cfg);
10362
10363                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
10364                                 if (cfg->compile_aot) {
10365                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
10366                                 } else {
10367                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
10368                                 }
10369                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
10370                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10371                                 ip += 11;
10372                         }
10373
10374                         break;
10375                 }
10376                 case CEE_LDLEN:
10377                         CHECK_STACK (1);
10378                         --sp;
10379                         if (sp [0]->type != STACK_OBJ)
10380                                 UNVERIFIED;
10381
10382                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
10383                         ins->dreg = alloc_preg (cfg);
10384                         ins->sreg1 = sp [0]->dreg;
10385                         ins->type = STACK_I4;
10386                         /* This flag will be inherited by the decomposition */
10387                         ins->flags |= MONO_INST_FAULT;
10388                         MONO_ADD_INS (cfg->cbb, ins);
10389                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
10390                         cfg->cbb->has_array_access = TRUE;
10391                         ip ++;
10392                         *sp++ = ins;
10393                         break;
10394                 case CEE_LDELEMA:
10395                         CHECK_STACK (2);
10396                         sp -= 2;
10397                         CHECK_OPSIZE (5);
10398                         if (sp [0]->type != STACK_OBJ)
10399                                 UNVERIFIED;
10400
10401                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10402
10403                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
10404                         CHECK_TYPELOAD (klass);
10405                         /* we need to make sure that this array is exactly the type it needs
10406                          * to be for correctness. the wrappers are lax with their usage
10407                          * so we need to ignore them here
10408                          */
10409                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
10410                                 MonoClass *array_class = mono_array_class_get (klass, 1);
10411                                 mini_emit_check_array_type (cfg, sp [0], array_class);
10412                                 CHECK_TYPELOAD (array_class);
10413                         }
10414
10415                         readonly = FALSE;
10416                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10417                         *sp++ = ins;
10418                         ip += 5;
10419                         break;
10420                 case CEE_LDELEM:
10421                 case CEE_LDELEM_I1:
10422                 case CEE_LDELEM_U1:
10423                 case CEE_LDELEM_I2:
10424                 case CEE_LDELEM_U2:
10425                 case CEE_LDELEM_I4:
10426                 case CEE_LDELEM_U4:
10427                 case CEE_LDELEM_I8:
10428                 case CEE_LDELEM_I:
10429                 case CEE_LDELEM_R4:
10430                 case CEE_LDELEM_R8:
10431                 case CEE_LDELEM_REF: {
10432                         MonoInst *addr;
10433
10434                         CHECK_STACK (2);
10435                         sp -= 2;
10436
10437                         if (*ip == CEE_LDELEM) {
10438                                 CHECK_OPSIZE (5);
10439                                 token = read32 (ip + 1);
10440                                 klass = mini_get_class (method, token, generic_context);
10441                                 CHECK_TYPELOAD (klass);
10442                                 mono_class_init (klass);
10443                         }
10444                         else
10445                                 klass = array_access_to_klass (*ip);
10446
10447                         if (sp [0]->type != STACK_OBJ)
10448                                 UNVERIFIED;
10449
10450                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10451
10452                         if (mini_is_gsharedvt_klass (cfg, klass)) {
10453                                 // FIXME-VT: OP_ICONST optimization
10454                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10455                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10456                                 ins->opcode = OP_LOADV_MEMBASE;
10457                         } else if (sp [1]->opcode == OP_ICONST) {
10458                                 int array_reg = sp [0]->dreg;
10459                                 int index_reg = sp [1]->dreg;
10460                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
10461
10462                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
10463                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
10464                         } else {
10465                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
10466                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
10467                         }
10468                         *sp++ = ins;
10469                         if (*ip == CEE_LDELEM)
10470                                 ip += 5;
10471                         else
10472                                 ++ip;
10473                         break;
10474                 }
10475                 case CEE_STELEM_I:
10476                 case CEE_STELEM_I1:
10477                 case CEE_STELEM_I2:
10478                 case CEE_STELEM_I4:
10479                 case CEE_STELEM_I8:
10480                 case CEE_STELEM_R4:
10481                 case CEE_STELEM_R8:
10482                 case CEE_STELEM_REF:
10483                 case CEE_STELEM: {
10484                         CHECK_STACK (3);
10485                         sp -= 3;
10486
10487                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
10488
10489                         if (*ip == CEE_STELEM) {
10490                                 CHECK_OPSIZE (5);
10491                                 token = read32 (ip + 1);
10492                                 klass = mini_get_class (method, token, generic_context);
10493                                 CHECK_TYPELOAD (klass);
10494                                 mono_class_init (klass);
10495                         }
10496                         else
10497                                 klass = array_access_to_klass (*ip);
10498
10499                         if (sp [0]->type != STACK_OBJ)
10500                                 UNVERIFIED;
10501
10502                         emit_array_store (cfg, klass, sp, TRUE);
10503
10504                         if (*ip == CEE_STELEM)
10505                                 ip += 5;
10506                         else
10507                                 ++ip;
10508                         inline_costs += 1;
10509                         break;
10510                 }
10511                 case CEE_CKFINITE: {
10512                         CHECK_STACK (1);
10513                         --sp;
10514
10515                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
10516                         ins->sreg1 = sp [0]->dreg;
10517                         ins->dreg = alloc_freg (cfg);
10518                         ins->type = STACK_R8;
10519                         MONO_ADD_INS (bblock, ins);
10520
10521                         *sp++ = mono_decompose_opcode (cfg, ins);
10522
10523                         ++ip;
10524                         break;
10525                 }
10526                 case CEE_REFANYVAL: {
10527                         MonoInst *src_var, *src;
10528
10529                         int klass_reg = alloc_preg (cfg);
10530                         int dreg = alloc_preg (cfg);
10531
10532                         GSHAREDVT_FAILURE (*ip);
10533
10534                         CHECK_STACK (1);
10535                         MONO_INST_NEW (cfg, ins, *ip);
10536                         --sp;
10537                         CHECK_OPSIZE (5);
10538                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10539                         CHECK_TYPELOAD (klass);
10540                         mono_class_init (klass);
10541
10542                         context_used = mini_class_check_context_used (cfg, klass);
10543
10544                         // FIXME:
10545                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10546                         if (!src_var)
10547                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10548                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10549                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
10550
10551                         if (context_used) {
10552                                 MonoInst *klass_ins;
10553
10554                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
10555                                                 klass, MONO_RGCTX_INFO_KLASS);
10556
10557                                 // FIXME:
10558                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
10559                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
10560                         } else {
10561                                 mini_emit_class_check (cfg, klass_reg, klass);
10562                         }
10563                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
10564                         ins->type = STACK_MP;
10565                         *sp++ = ins;
10566                         ip += 5;
10567                         break;
10568                 }
10569                 case CEE_MKREFANY: {
10570                         MonoInst *loc, *addr;
10571
10572                         GSHAREDVT_FAILURE (*ip);
10573
10574                         CHECK_STACK (1);
10575                         MONO_INST_NEW (cfg, ins, *ip);
10576                         --sp;
10577                         CHECK_OPSIZE (5);
10578                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
10579                         CHECK_TYPELOAD (klass);
10580                         mono_class_init (klass);
10581
10582                         context_used = mini_class_check_context_used (cfg, klass);
10583
10584                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
10585                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
10586
10587                         if (context_used) {
10588                                 MonoInst *const_ins;
10589                                 int type_reg = alloc_preg (cfg);
10590
10591                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
10592                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
10593                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10594                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10595                         } else if (cfg->compile_aot) {
10596                                 int const_reg = alloc_preg (cfg);
10597                                 int type_reg = alloc_preg (cfg);
10598
10599                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
10600                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
10601                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
10602                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
10603                         } else {
10604                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
10605                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
10606                         }
10607                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
10608
10609                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
10610                         ins->type = STACK_VTYPE;
10611                         ins->klass = mono_defaults.typed_reference_class;
10612                         *sp++ = ins;
10613                         ip += 5;
10614                         break;
10615                 }
10616                 case CEE_LDTOKEN: {
10617                         gpointer handle;
10618                         MonoClass *handle_class;
10619
10620                         CHECK_STACK_OVF (1);
10621
10622                         CHECK_OPSIZE (5);
10623                         n = read32 (ip + 1);
10624
10625                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
10626                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
10627                                 handle = mono_method_get_wrapper_data (method, n);
10628                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
10629                                 if (handle_class == mono_defaults.typehandle_class)
10630                                         handle = &((MonoClass*)handle)->byval_arg;
10631                         }
10632                         else {
10633                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
10634                         }
10635                         if (!handle)
10636                                 LOAD_ERROR;
10637                         mono_class_init (handle_class);
10638                         if (cfg->generic_sharing_context) {
10639                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
10640                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
10641                                         /* This case handles ldtoken
10642                                            of an open type, like for
10643                                            typeof(Gen<>). */
10644                                         context_used = 0;
10645                                 } else if (handle_class == mono_defaults.typehandle_class) {
10646                                         /* If we get a MONO_TYPE_CLASS
10647                                            then we need to provide the
10648                                            open type, not an
10649                                            instantiation of it. */
10650                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
10651                                                 context_used = 0;
10652                                         else
10653                                                 context_used = mini_class_check_context_used (cfg, mono_class_from_mono_type (handle));
10654                                 } else if (handle_class == mono_defaults.fieldhandle_class)
10655                                         context_used = mini_class_check_context_used (cfg, ((MonoClassField*)handle)->parent);
10656                                 else if (handle_class == mono_defaults.methodhandle_class)
10657                                         context_used = mini_method_check_context_used (cfg, handle);
10658                                 else
10659                                         g_assert_not_reached ();
10660                         }
10661
10662                         if ((cfg->opt & MONO_OPT_SHARED) &&
10663                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
10664                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
10665                                 MonoInst *addr, *vtvar, *iargs [3];
10666                                 int method_context_used;
10667
10668                                 method_context_used = mini_method_check_context_used (cfg, method);
10669
10670                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
10671
10672                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
10673                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
10674                                 if (method_context_used) {
10675                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
10676                                                 method, MONO_RGCTX_INFO_METHOD);
10677                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
10678                                 } else {
10679                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
10680                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
10681                                 }
10682                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10683
10684                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10685
10686                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10687                         } else {
10688                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
10689                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
10690                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
10691                                         (cmethod->klass == mono_defaults.systemtype_class) &&
10692                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
10693                                         MonoClass *tclass = mono_class_from_mono_type (handle);
10694
10695                                         mono_class_init (tclass);
10696                                         if (context_used) {
10697                                                 ins = emit_get_rgctx_klass (cfg, context_used,
10698                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
10699                                         } else if (cfg->compile_aot) {
10700                                                 if (method->wrapper_type) {
10701                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
10702                                                                 /* Special case for static synchronized wrappers */
10703                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
10704                                                         } else {
10705                                                                 /* FIXME: n is not a normal token */
10706                                                                 cfg->disable_aot = TRUE;
10707                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
10708                                                         }
10709                                                 } else {
10710                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
10711                                                 }
10712                                         } else {
10713                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
10714                                         }
10715                                         ins->type = STACK_OBJ;
10716                                         ins->klass = cmethod->klass;
10717                                         ip += 5;
10718                                 } else {
10719                                         MonoInst *addr, *vtvar;
10720
10721                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
10722
10723                                         if (context_used) {
10724                                                 if (handle_class == mono_defaults.typehandle_class) {
10725                                                         ins = emit_get_rgctx_klass (cfg, context_used,
10726                                                                         mono_class_from_mono_type (handle),
10727                                                                         MONO_RGCTX_INFO_TYPE);
10728                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
10729                                                         ins = emit_get_rgctx_method (cfg, context_used,
10730                                                                         handle, MONO_RGCTX_INFO_METHOD);
10731                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
10732                                                         ins = emit_get_rgctx_field (cfg, context_used,
10733                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
10734                                                 } else {
10735                                                         g_assert_not_reached ();
10736                                                 }
10737                                         } else if (cfg->compile_aot) {
10738                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n, generic_context);
10739                                         } else {
10740                                                 EMIT_NEW_PCONST (cfg, ins, handle);
10741                                         }
10742                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
10743                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
10744                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
10745                                 }
10746                         }
10747
10748                         *sp++ = ins;
10749                         ip += 5;
10750                         break;
10751                 }
10752                 case CEE_THROW:
10753                         CHECK_STACK (1);
10754                         MONO_INST_NEW (cfg, ins, OP_THROW);
10755                         --sp;
10756                         ins->sreg1 = sp [0]->dreg;
10757                         ip++;
10758                         bblock->out_of_line = TRUE;
10759                         MONO_ADD_INS (bblock, ins);
10760                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
10761                         MONO_ADD_INS (bblock, ins);
10762                         sp = stack_start;
10763                         
10764                         link_bblock (cfg, bblock, end_bblock);
10765                         start_new_bblock = 1;
10766                         break;
10767                 case CEE_ENDFINALLY:
10768                         /* mono_save_seq_point_info () depends on this */
10769                         if (sp != stack_start)
10770                                 emit_seq_point (cfg, method, ip, FALSE, FALSE);
10771                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
10772                         MONO_ADD_INS (bblock, ins);
10773                         ip++;
10774                         start_new_bblock = 1;
10775
10776                         /*
10777                          * Control will leave the method so empty the stack, otherwise
10778                          * the next basic block will start with a nonempty stack.
10779                          */
10780                         while (sp != stack_start) {
10781                                 sp--;
10782                         }
10783                         break;
10784                 case CEE_LEAVE:
10785                 case CEE_LEAVE_S: {
10786                         GList *handlers;
10787
10788                         if (*ip == CEE_LEAVE) {
10789                                 CHECK_OPSIZE (5);
10790                                 target = ip + 5 + (gint32)read32(ip + 1);
10791                         } else {
10792                                 CHECK_OPSIZE (2);
10793                                 target = ip + 2 + (signed char)(ip [1]);
10794                         }
10795
10796                         /* empty the stack */
10797                         while (sp != stack_start) {
10798                                 sp--;
10799                         }
10800
10801                         /* 
10802                          * If this leave statement is in a catch block, check for a
10803                          * pending exception, and rethrow it if necessary.
10804                          * We avoid doing this in runtime invoke wrappers, since those are called
10805                          * by native code which excepts the wrapper to catch all exceptions.
10806                          */
10807                         for (i = 0; i < header->num_clauses; ++i) {
10808                                 MonoExceptionClause *clause = &header->clauses [i];
10809
10810                                 /* 
10811                                  * Use <= in the final comparison to handle clauses with multiple
10812                                  * leave statements, like in bug #78024.
10813                                  * The ordering of the exception clauses guarantees that we find the
10814                                  * innermost clause.
10815                                  */
10816                                 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) {
10817                                         MonoInst *exc_ins;
10818                                         MonoBasicBlock *dont_throw;
10819
10820                                         /*
10821                                           MonoInst *load;
10822
10823                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
10824                                         */
10825
10826                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
10827
10828                                         NEW_BBLOCK (cfg, dont_throw);
10829
10830                                         /*
10831                                          * Currently, we always rethrow the abort exception, despite the 
10832                                          * fact that this is not correct. See thread6.cs for an example. 
10833                                          * But propagating the abort exception is more important than 
10834                                          * getting the sematics right.
10835                                          */
10836                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
10837                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
10838                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
10839
10840                                         MONO_START_BB (cfg, dont_throw);
10841                                         bblock = cfg->cbb;
10842                                 }
10843                         }
10844
10845                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
10846                                 GList *tmp;
10847                                 MonoExceptionClause *clause;
10848
10849                                 for (tmp = handlers; tmp; tmp = tmp->next) {
10850                                         clause = tmp->data;
10851                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
10852                                         g_assert (tblock);
10853                                         link_bblock (cfg, bblock, tblock);
10854                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
10855                                         ins->inst_target_bb = tblock;
10856                                         ins->inst_eh_block = clause;
10857                                         MONO_ADD_INS (bblock, ins);
10858                                         bblock->has_call_handler = 1;
10859                                         if (COMPILE_LLVM (cfg)) {
10860                                                 MonoBasicBlock *target_bb;
10861
10862                                                 /* 
10863                                                  * Link the finally bblock with the target, since it will
10864                                                  * conceptually branch there.
10865                                                  * FIXME: Have to link the bblock containing the endfinally.
10866                                                  */
10867                                                 GET_BBLOCK (cfg, target_bb, target);
10868                                                 link_bblock (cfg, tblock, target_bb);
10869                                         }
10870                                 }
10871                                 g_list_free (handlers);
10872                         } 
10873
10874                         MONO_INST_NEW (cfg, ins, OP_BR);
10875                         MONO_ADD_INS (bblock, ins);
10876                         GET_BBLOCK (cfg, tblock, target);
10877                         link_bblock (cfg, bblock, tblock);
10878                         ins->inst_target_bb = tblock;
10879                         start_new_bblock = 1;
10880
10881                         if (*ip == CEE_LEAVE)
10882                                 ip += 5;
10883                         else
10884                                 ip += 2;
10885
10886                         break;
10887                 }
10888
10889                         /*
10890                          * Mono specific opcodes
10891                          */
10892                 case MONO_CUSTOM_PREFIX: {
10893
10894                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
10895
10896                         CHECK_OPSIZE (2);
10897                         switch (ip [1]) {
10898                         case CEE_MONO_ICALL: {
10899                                 gpointer func;
10900                                 MonoJitICallInfo *info;
10901
10902                                 token = read32 (ip + 2);
10903                                 func = mono_method_get_wrapper_data (method, token);
10904                                 info = mono_find_jit_icall_by_addr (func);
10905                                 if (!info)
10906                                         g_error ("Could not find icall address in wrapper %s", mono_method_full_name (method, 1));
10907                                 g_assert (info);
10908
10909                                 CHECK_STACK (info->sig->param_count);
10910                                 sp -= info->sig->param_count;
10911
10912                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
10913                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
10914                                         *sp++ = ins;
10915
10916                                 ip += 6;
10917                                 inline_costs += 10 * num_calls++;
10918
10919                                 break;
10920                         }
10921                         case CEE_MONO_LDPTR: {
10922                                 gpointer ptr;
10923
10924                                 CHECK_STACK_OVF (1);
10925                                 CHECK_OPSIZE (6);
10926                                 token = read32 (ip + 2);
10927
10928                                 ptr = mono_method_get_wrapper_data (method, token);
10929                                 /* FIXME: Generalize this */
10930                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
10931                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
10932                                         *sp++ = ins;
10933                                         ip += 6;
10934                                         break;
10935                                 }
10936                                 EMIT_NEW_PCONST (cfg, ins, ptr);
10937                                 *sp++ = ins;
10938                                 ip += 6;
10939                                 inline_costs += 10 * num_calls++;
10940                                 /* Can't embed random pointers into AOT code */
10941                                 cfg->disable_aot = 1;
10942                                 break;
10943                         }
10944                         case CEE_MONO_JIT_ICALL_ADDR: {
10945                                 MonoJitICallInfo *callinfo;
10946                                 gpointer ptr;
10947
10948                                 CHECK_STACK_OVF (1);
10949                                 CHECK_OPSIZE (6);
10950                                 token = read32 (ip + 2);
10951
10952                                 ptr = mono_method_get_wrapper_data (method, token);
10953                                 callinfo = mono_find_jit_icall_by_addr (ptr);
10954                                 g_assert (callinfo);
10955                                 EMIT_NEW_JIT_ICALL_ADDRCONST (cfg, ins, (char*)callinfo->name);
10956                                 *sp++ = ins;
10957                                 ip += 6;
10958                                 inline_costs += 10 * num_calls++;
10959                                 break;
10960                         }
10961                         case CEE_MONO_ICALL_ADDR: {
10962                                 MonoMethod *cmethod;
10963                                 gpointer ptr;
10964
10965                                 CHECK_STACK_OVF (1);
10966                                 CHECK_OPSIZE (6);
10967                                 token = read32 (ip + 2);
10968
10969                                 cmethod = mono_method_get_wrapper_data (method, token);
10970
10971                                 if (cfg->compile_aot) {
10972                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
10973                                 } else {
10974                                         ptr = mono_lookup_internal_call (cmethod);
10975                                         g_assert (ptr);
10976                                         EMIT_NEW_PCONST (cfg, ins, ptr);
10977                                 }
10978                                 *sp++ = ins;
10979                                 ip += 6;
10980                                 break;
10981                         }
10982                         case CEE_MONO_VTADDR: {
10983                                 MonoInst *src_var, *src;
10984
10985                                 CHECK_STACK (1);
10986                                 --sp;
10987
10988                                 // FIXME:
10989                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10990                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
10991                                 *sp++ = src;
10992                                 ip += 2;
10993                                 break;
10994                         }
10995                         case CEE_MONO_NEWOBJ: {
10996                                 MonoInst *iargs [2];
10997
10998                                 CHECK_STACK_OVF (1);
10999                                 CHECK_OPSIZE (6);
11000                                 token = read32 (ip + 2);
11001                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11002                                 mono_class_init (klass);
11003                                 NEW_DOMAINCONST (cfg, iargs [0]);
11004                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
11005                                 NEW_CLASSCONST (cfg, iargs [1], klass);
11006                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
11007                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
11008                                 ip += 6;
11009                                 inline_costs += 10 * num_calls++;
11010                                 break;
11011                         }
11012                         case CEE_MONO_OBJADDR:
11013                                 CHECK_STACK (1);
11014                                 --sp;
11015                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
11016                                 ins->dreg = alloc_ireg_mp (cfg);
11017                                 ins->sreg1 = sp [0]->dreg;
11018                                 ins->type = STACK_MP;
11019                                 MONO_ADD_INS (cfg->cbb, ins);
11020                                 *sp++ = ins;
11021                                 ip += 2;
11022                                 break;
11023                         case CEE_MONO_LDNATIVEOBJ:
11024                                 /*
11025                                  * Similar to LDOBJ, but instead load the unmanaged 
11026                                  * representation of the vtype to the stack.
11027                                  */
11028                                 CHECK_STACK (1);
11029                                 CHECK_OPSIZE (6);
11030                                 --sp;
11031                                 token = read32 (ip + 2);
11032                                 klass = mono_method_get_wrapper_data (method, token);
11033                                 g_assert (klass->valuetype);
11034                                 mono_class_init (klass);
11035
11036                                 {
11037                                         MonoInst *src, *dest, *temp;
11038
11039                                         src = sp [0];
11040                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
11041                                         temp->backend.is_pinvoke = 1;
11042                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
11043                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
11044
11045                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
11046                                         dest->type = STACK_VTYPE;
11047                                         dest->klass = klass;
11048
11049                                         *sp ++ = dest;
11050                                         ip += 6;
11051                                 }
11052                                 break;
11053                         case CEE_MONO_RETOBJ: {
11054                                 /*
11055                                  * Same as RET, but return the native representation of a vtype
11056                                  * to the caller.
11057                                  */
11058                                 g_assert (cfg->ret);
11059                                 g_assert (mono_method_signature (method)->pinvoke); 
11060                                 CHECK_STACK (1);
11061                                 --sp;
11062                                 
11063                                 CHECK_OPSIZE (6);
11064                                 token = read32 (ip + 2);    
11065                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11066
11067                                 if (!cfg->vret_addr) {
11068                                         g_assert (cfg->ret_var_is_local);
11069
11070                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
11071                                 } else {
11072                                         EMIT_NEW_RETLOADA (cfg, ins);
11073                                 }
11074                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
11075                                 
11076                                 if (sp != stack_start)
11077                                         UNVERIFIED;
11078                                 
11079                                 MONO_INST_NEW (cfg, ins, OP_BR);
11080                                 ins->inst_target_bb = end_bblock;
11081                                 MONO_ADD_INS (bblock, ins);
11082                                 link_bblock (cfg, bblock, end_bblock);
11083                                 start_new_bblock = 1;
11084                                 ip += 6;
11085                                 break;
11086                         }
11087                         case CEE_MONO_CISINST:
11088                         case CEE_MONO_CCASTCLASS: {
11089                                 int token;
11090                                 CHECK_STACK (1);
11091                                 --sp;
11092                                 CHECK_OPSIZE (6);
11093                                 token = read32 (ip + 2);
11094                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
11095                                 if (ip [1] == CEE_MONO_CISINST)
11096                                         ins = handle_cisinst (cfg, klass, sp [0]);
11097                                 else
11098                                         ins = handle_ccastclass (cfg, klass, sp [0]);
11099                                 bblock = cfg->cbb;
11100                                 *sp++ = ins;
11101                                 ip += 6;
11102                                 break;
11103                         }
11104                         case CEE_MONO_SAVE_LMF:
11105                         case CEE_MONO_RESTORE_LMF:
11106 #ifdef MONO_ARCH_HAVE_LMF_OPS
11107                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
11108                                 MONO_ADD_INS (bblock, ins);
11109                                 cfg->need_lmf_area = TRUE;
11110 #endif
11111                                 ip += 2;
11112                                 break;
11113                         case CEE_MONO_CLASSCONST:
11114                                 CHECK_STACK_OVF (1);
11115                                 CHECK_OPSIZE (6);
11116                                 token = read32 (ip + 2);
11117                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
11118                                 *sp++ = ins;
11119                                 ip += 6;
11120                                 inline_costs += 10 * num_calls++;
11121                                 break;
11122                         case CEE_MONO_NOT_TAKEN:
11123                                 bblock->out_of_line = TRUE;
11124                                 ip += 2;
11125                                 break;
11126                         case CEE_MONO_TLS:
11127                                 CHECK_STACK_OVF (1);
11128                                 CHECK_OPSIZE (6);
11129                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
11130                                 ins->dreg = alloc_preg (cfg);
11131                                 ins->inst_offset = (gint32)read32 (ip + 2);
11132                                 ins->type = STACK_PTR;
11133                                 MONO_ADD_INS (bblock, ins);
11134                                 *sp++ = ins;
11135                                 ip += 6;
11136                                 break;
11137                         case CEE_MONO_DYN_CALL: {
11138                                 MonoCallInst *call;
11139
11140                                 /* It would be easier to call a trampoline, but that would put an
11141                                  * extra frame on the stack, confusing exception handling. So
11142                                  * implement it inline using an opcode for now.
11143                                  */
11144
11145                                 if (!cfg->dyn_call_var) {
11146                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11147                                         /* prevent it from being register allocated */
11148                                         cfg->dyn_call_var->flags |= MONO_INST_INDIRECT;
11149                                 }
11150
11151                                 /* Has to use a call inst since it local regalloc expects it */
11152                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
11153                                 ins = (MonoInst*)call;
11154                                 sp -= 2;
11155                                 ins->sreg1 = sp [0]->dreg;
11156                                 ins->sreg2 = sp [1]->dreg;
11157                                 MONO_ADD_INS (bblock, ins);
11158
11159 #ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
11160                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
11161 #endif
11162
11163                                 ip += 2;
11164                                 inline_costs += 10 * num_calls++;
11165
11166                                 break;
11167                         }
11168                         case CEE_MONO_MEMORY_BARRIER: {
11169                                 CHECK_OPSIZE (5);
11170                                 emit_memory_barrier (cfg, (int)read32 (ip + 1));
11171                                 ip += 5;
11172                                 break;
11173                         }
11174                         case CEE_MONO_JIT_ATTACH: {
11175                                 MonoInst *args [16];
11176                                 MonoInst *ad_ins, *lmf_ins;
11177                                 MonoBasicBlock *next_bb = NULL;
11178
11179                                 cfg->orig_domain_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
11180
11181                                 EMIT_NEW_PCONST (cfg, ins, NULL);
11182                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11183
11184 #if TARGET_WIN32
11185                                 ad_ins = NULL;
11186                                 lmf_ins = NULL;
11187 #else
11188                                 ad_ins = mono_get_domain_intrinsic (cfg);
11189                                 lmf_ins = mono_get_lmf_intrinsic (cfg);
11190 #endif
11191
11192                                 if (MONO_ARCH_HAVE_TLS_GET && ad_ins && lmf_ins) {
11193                                         NEW_BBLOCK (cfg, next_bb);
11194
11195                                         MONO_ADD_INS (cfg->cbb, ad_ins);
11196                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, ad_ins->dreg, 0);
11197                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11198
11199                                         MONO_ADD_INS (cfg->cbb, lmf_ins);
11200                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, lmf_ins->dreg, 0);
11201                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, next_bb);
11202                                 }
11203
11204                                 if (cfg->compile_aot) {
11205                                         /* AOT code is only used in the root domain */
11206                                         EMIT_NEW_PCONST (cfg, args [0], NULL);
11207                                 } else {
11208                                         EMIT_NEW_PCONST (cfg, args [0], cfg->domain);
11209                                 }
11210                                 ins = mono_emit_jit_icall (cfg, mono_jit_thread_attach, args);
11211                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->orig_domain_var->dreg, ins->dreg);
11212
11213                                 if (next_bb) {
11214                                         MONO_START_BB (cfg, next_bb);
11215                                         bblock = cfg->cbb;
11216                                 }
11217                                 ip += 2;
11218                                 break;
11219                         }
11220                         case CEE_MONO_JIT_DETACH: {
11221                                 MonoInst *args [16];
11222
11223                                 /* Restore the original domain */
11224                                 dreg = alloc_ireg (cfg);
11225                                 EMIT_NEW_UNALU (cfg, args [0], OP_MOVE, dreg, cfg->orig_domain_var->dreg);
11226                                 mono_emit_jit_icall (cfg, mono_jit_set_domain, args);
11227                                 ip += 2;
11228                                 break;
11229                         }
11230                         default:
11231                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
11232                                 break;
11233                         }
11234                         break;
11235                 }
11236
11237                 case CEE_PREFIX1: {
11238                         CHECK_OPSIZE (2);
11239                         switch (ip [1]) {
11240                         case CEE_ARGLIST: {
11241                                 /* somewhat similar to LDTOKEN */
11242                                 MonoInst *addr, *vtvar;
11243                                 CHECK_STACK_OVF (1);
11244                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
11245
11246                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
11247                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
11248
11249                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
11250                                 ins->type = STACK_VTYPE;
11251                                 ins->klass = mono_defaults.argumenthandle_class;
11252                                 *sp++ = ins;
11253                                 ip += 2;
11254                                 break;
11255                         }
11256                         case CEE_CEQ:
11257                         case CEE_CGT:
11258                         case CEE_CGT_UN:
11259                         case CEE_CLT:
11260                         case CEE_CLT_UN: {
11261                                 MonoInst *cmp;
11262                                 CHECK_STACK (2);
11263                                 /*
11264                                  * The following transforms:
11265                                  *    CEE_CEQ    into OP_CEQ
11266                                  *    CEE_CGT    into OP_CGT
11267                                  *    CEE_CGT_UN into OP_CGT_UN
11268                                  *    CEE_CLT    into OP_CLT
11269                                  *    CEE_CLT_UN into OP_CLT_UN
11270                                  */
11271                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
11272                                 
11273                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
11274                                 sp -= 2;
11275                                 cmp->sreg1 = sp [0]->dreg;
11276                                 cmp->sreg2 = sp [1]->dreg;
11277                                 type_from_op (cmp, sp [0], sp [1]);
11278                                 CHECK_TYPE (cmp);
11279                                 if ((sp [0]->type == STACK_I8) || ((SIZEOF_VOID_P == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
11280                                         cmp->opcode = OP_LCOMPARE;
11281                                 else if (sp [0]->type == STACK_R8)
11282                                         cmp->opcode = OP_FCOMPARE;
11283                                 else
11284                                         cmp->opcode = OP_ICOMPARE;
11285                                 MONO_ADD_INS (bblock, cmp);
11286                                 ins->type = STACK_I4;
11287                                 ins->dreg = alloc_dreg (cfg, ins->type);
11288                                 type_from_op (ins, sp [0], sp [1]);
11289
11290                                 if (cmp->opcode == OP_FCOMPARE) {
11291                                         /*
11292                                          * The backends expect the fceq opcodes to do the
11293                                          * comparison too.
11294                                          */
11295                                         cmp->opcode = OP_NOP;
11296                                         ins->sreg1 = cmp->sreg1;
11297                                         ins->sreg2 = cmp->sreg2;
11298                                 }
11299                                 MONO_ADD_INS (bblock, ins);
11300                                 *sp++ = ins;
11301                                 ip += 2;
11302                                 break;
11303                         }
11304                         case CEE_LDFTN: {
11305                                 MonoInst *argconst;
11306                                 MonoMethod *cil_method;
11307
11308                                 CHECK_STACK_OVF (1);
11309                                 CHECK_OPSIZE (6);
11310                                 n = read32 (ip + 2);
11311                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11312                                 if (!cmethod || mono_loader_get_last_error ())
11313                                         LOAD_ERROR;
11314                                 mono_class_init (cmethod->klass);
11315
11316                                 mono_save_token_info (cfg, image, n, cmethod);
11317
11318                                 context_used = mini_method_check_context_used (cfg, cmethod);
11319
11320                                 cil_method = cmethod;
11321                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
11322                                         METHOD_ACCESS_FAILURE;
11323
11324                                 if (mono_security_cas_enabled ()) {
11325                                         if (check_linkdemand (cfg, method, cmethod))
11326                                                 INLINE_FAILURE ("linkdemand");
11327                                         CHECK_CFG_EXCEPTION;
11328                                 } else if (mono_security_core_clr_enabled ()) {
11329                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11330                                 }
11331
11332                                 /* 
11333                                  * Optimize the common case of ldftn+delegate creation
11334                                  */
11335                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
11336                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
11337                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
11338                                                 MonoInst *target_ins;
11339                                                 MonoMethod *invoke;
11340                                                 int invoke_context_used;
11341
11342                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
11343                                                 if (!invoke || !mono_method_signature (invoke))
11344                                                         LOAD_ERROR;
11345
11346                                                 invoke_context_used = mini_method_check_context_used (cfg, invoke);
11347
11348                                                 target_ins = sp [-1];
11349
11350                                                 if (mono_security_core_clr_enabled ())
11351                                                         ensure_method_is_allowed_to_call_method (cfg, method, ctor_method, bblock, ip);
11352
11353                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
11354                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
11355                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
11356                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
11357                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
11358                                                         }
11359                                                 }
11360
11361 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
11362                                                 /* FIXME: SGEN support */
11363                                                 if (invoke_context_used == 0) {
11364                                                         ip += 6;
11365                                                         if (cfg->verbose_level > 3)
11366                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
11367                                                         sp --;
11368                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
11369                                                         CHECK_CFG_EXCEPTION;
11370                                                         ip += 5;                        
11371                                                         sp ++;
11372                                                         break;
11373                                                 }
11374 #endif
11375                                         }
11376                                 }
11377
11378                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
11379                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
11380                                 *sp++ = ins;
11381                                 
11382                                 ip += 6;
11383                                 inline_costs += 10 * num_calls++;
11384                                 break;
11385                         }
11386                         case CEE_LDVIRTFTN: {
11387                                 MonoInst *args [2];
11388
11389                                 CHECK_STACK (1);
11390                                 CHECK_OPSIZE (6);
11391                                 n = read32 (ip + 2);
11392                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
11393                                 if (!cmethod || mono_loader_get_last_error ())
11394                                         LOAD_ERROR;
11395                                 mono_class_init (cmethod->klass);
11396  
11397                                 context_used = mini_method_check_context_used (cfg, cmethod);
11398
11399                                 if (mono_security_cas_enabled ()) {
11400                                         if (check_linkdemand (cfg, method, cmethod))
11401                                                 INLINE_FAILURE ("linkdemand");
11402                                         CHECK_CFG_EXCEPTION;
11403                                 } else if (mono_security_core_clr_enabled ()) {
11404                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
11405                                 }
11406
11407                                 --sp;
11408                                 args [0] = *sp;
11409
11410                                 args [1] = emit_get_rgctx_method (cfg, context_used,
11411                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
11412
11413                                 if (context_used)
11414                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
11415                                 else
11416                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
11417
11418                                 ip += 6;
11419                                 inline_costs += 10 * num_calls++;
11420                                 break;
11421                         }
11422                         case CEE_LDARG:
11423                                 CHECK_STACK_OVF (1);
11424                                 CHECK_OPSIZE (4);
11425                                 n = read16 (ip + 2);
11426                                 CHECK_ARG (n);
11427                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
11428                                 *sp++ = ins;
11429                                 ip += 4;
11430                                 break;
11431                         case CEE_LDARGA:
11432                                 CHECK_STACK_OVF (1);
11433                                 CHECK_OPSIZE (4);
11434                                 n = read16 (ip + 2);
11435                                 CHECK_ARG (n);
11436                                 NEW_ARGLOADA (cfg, ins, n);
11437                                 MONO_ADD_INS (cfg->cbb, ins);
11438                                 *sp++ = ins;
11439                                 ip += 4;
11440                                 break;
11441                         case CEE_STARG:
11442                                 CHECK_STACK (1);
11443                                 --sp;
11444                                 CHECK_OPSIZE (4);
11445                                 n = read16 (ip + 2);
11446                                 CHECK_ARG (n);
11447                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
11448                                         UNVERIFIED;
11449                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
11450                                 ip += 4;
11451                                 break;
11452                         case CEE_LDLOC:
11453                                 CHECK_STACK_OVF (1);
11454                                 CHECK_OPSIZE (4);
11455                                 n = read16 (ip + 2);
11456                                 CHECK_LOCAL (n);
11457                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
11458                                 *sp++ = ins;
11459                                 ip += 4;
11460                                 break;
11461                         case CEE_LDLOCA: {
11462                                 unsigned char *tmp_ip;
11463                                 CHECK_STACK_OVF (1);
11464                                 CHECK_OPSIZE (4);
11465                                 n = read16 (ip + 2);
11466                                 CHECK_LOCAL (n);
11467
11468                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
11469                                         ip = tmp_ip;
11470                                         inline_costs += 1;
11471                                         break;
11472                                 }                       
11473                                 
11474                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
11475                                 *sp++ = ins;
11476                                 ip += 4;
11477                                 break;
11478                         }
11479                         case CEE_STLOC:
11480                                 CHECK_STACK (1);
11481                                 --sp;
11482                                 CHECK_OPSIZE (4);
11483                                 n = read16 (ip + 2);
11484                                 CHECK_LOCAL (n);
11485                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
11486                                         UNVERIFIED;
11487                                 emit_stloc_ir (cfg, sp, header, n);
11488                                 ip += 4;
11489                                 inline_costs += 1;
11490                                 break;
11491                         case CEE_LOCALLOC:
11492                                 CHECK_STACK (1);
11493                                 --sp;
11494                                 if (sp != stack_start) 
11495                                         UNVERIFIED;
11496                                 if (cfg->method != method) 
11497                                         /* 
11498                                          * Inlining this into a loop in a parent could lead to 
11499                                          * stack overflows which is different behavior than the
11500                                          * non-inlined case, thus disable inlining in this case.
11501                                          */
11502                                         goto inline_failure;
11503
11504                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
11505                                 ins->dreg = alloc_preg (cfg);
11506                                 ins->sreg1 = sp [0]->dreg;
11507                                 ins->type = STACK_PTR;
11508                                 MONO_ADD_INS (cfg->cbb, ins);
11509
11510                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
11511                                 if (init_locals)
11512                                         ins->flags |= MONO_INST_INIT;
11513
11514                                 *sp++ = ins;
11515                                 ip += 2;
11516                                 break;
11517                         case CEE_ENDFILTER: {
11518                                 MonoExceptionClause *clause, *nearest;
11519                                 int cc, nearest_num;
11520
11521                                 CHECK_STACK (1);
11522                                 --sp;
11523                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
11524                                         UNVERIFIED;
11525                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
11526                                 ins->sreg1 = (*sp)->dreg;
11527                                 MONO_ADD_INS (bblock, ins);
11528                                 start_new_bblock = 1;
11529                                 ip += 2;
11530
11531                                 nearest = NULL;
11532                                 nearest_num = 0;
11533                                 for (cc = 0; cc < header->num_clauses; ++cc) {
11534                                         clause = &header->clauses [cc];
11535                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
11536                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
11537                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
11538                                                 nearest = clause;
11539                                                 nearest_num = cc;
11540                                         }
11541                                 }
11542                                 g_assert (nearest);
11543                                 if ((ip - header->code) != nearest->handler_offset)
11544                                         UNVERIFIED;
11545
11546                                 break;
11547                         }
11548                         case CEE_UNALIGNED_:
11549                                 ins_flag |= MONO_INST_UNALIGNED;
11550                                 /* FIXME: record alignment? we can assume 1 for now */
11551                                 CHECK_OPSIZE (3);
11552                                 ip += 3;
11553                                 break;
11554                         case CEE_VOLATILE_:
11555                                 ins_flag |= MONO_INST_VOLATILE;
11556                                 ip += 2;
11557                                 break;
11558                         case CEE_TAIL_:
11559                                 ins_flag   |= MONO_INST_TAILCALL;
11560                                 cfg->flags |= MONO_CFG_HAS_TAIL;
11561                                 /* Can't inline tail calls at this time */
11562                                 inline_costs += 100000;
11563                                 ip += 2;
11564                                 break;
11565                         case CEE_INITOBJ:
11566                                 CHECK_STACK (1);
11567                                 --sp;
11568                                 CHECK_OPSIZE (6);
11569                                 token = read32 (ip + 2);
11570                                 klass = mini_get_class (method, token, generic_context);
11571                                 CHECK_TYPELOAD (klass);
11572                                 if (generic_class_is_reference_type (cfg, klass))
11573                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
11574                                 else
11575                                         mini_emit_initobj (cfg, *sp, NULL, klass);
11576                                 ip += 6;
11577                                 inline_costs += 1;
11578                                 break;
11579                         case CEE_CONSTRAINED_:
11580                                 CHECK_OPSIZE (6);
11581                                 token = read32 (ip + 2);
11582                                 constrained_call = mini_get_class (method, token, generic_context);
11583                                 CHECK_TYPELOAD (constrained_call);
11584                                 ip += 6;
11585                                 break;
11586                         case CEE_CPBLK:
11587                         case CEE_INITBLK: {
11588                                 MonoInst *iargs [3];
11589                                 CHECK_STACK (3);
11590                                 sp -= 3;
11591
11592                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
11593                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
11594                                 } else if ((ip [1] == CEE_INITBLK) && (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)) {
11595                                         /* emit_memset only works when val == 0 */
11596                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
11597                                 } else {
11598                                         iargs [0] = sp [0];
11599                                         iargs [1] = sp [1];
11600                                         iargs [2] = sp [2];
11601                                         if (ip [1] == CEE_CPBLK) {
11602                                                 MonoMethod *memcpy_method = get_memcpy_method ();
11603                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
11604                                         } else {
11605                                                 MonoMethod *memset_method = get_memset_method ();
11606                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
11607                                         }
11608                                 }
11609                                 ip += 2;
11610                                 inline_costs += 1;
11611                                 break;
11612                         }
11613                         case CEE_NO_:
11614                                 CHECK_OPSIZE (3);
11615                                 if (ip [2] & 0x1)
11616                                         ins_flag |= MONO_INST_NOTYPECHECK;
11617                                 if (ip [2] & 0x2)
11618                                         ins_flag |= MONO_INST_NORANGECHECK;
11619                                 /* we ignore the no-nullcheck for now since we
11620                                  * really do it explicitly only when doing callvirt->call
11621                                  */
11622                                 ip += 3;
11623                                 break;
11624                         case CEE_RETHROW: {
11625                                 MonoInst *load;
11626                                 int handler_offset = -1;
11627
11628                                 for (i = 0; i < header->num_clauses; ++i) {
11629                                         MonoExceptionClause *clause = &header->clauses [i];
11630                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
11631                                                 handler_offset = clause->handler_offset;
11632                                                 break;
11633                                         }
11634                                 }
11635
11636                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
11637
11638                                 g_assert (handler_offset != -1);
11639
11640                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
11641                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
11642                                 ins->sreg1 = load->dreg;
11643                                 MONO_ADD_INS (bblock, ins);
11644
11645                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
11646                                 MONO_ADD_INS (bblock, ins);
11647
11648                                 sp = stack_start;
11649                                 link_bblock (cfg, bblock, end_bblock);
11650                                 start_new_bblock = 1;
11651                                 ip += 2;
11652                                 break;
11653                         }
11654                         case CEE_SIZEOF: {
11655                                 guint32 val;
11656                                 int ialign;
11657
11658                                 GSHAREDVT_FAILURE (*ip);
11659
11660                                 CHECK_STACK_OVF (1);
11661                                 CHECK_OPSIZE (6);
11662                                 token = read32 (ip + 2);
11663                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic && !generic_context) {
11664                                         MonoType *type = mono_type_create_from_typespec (image, token);
11665                                         val = mono_type_size (type, &ialign);
11666                                 } else {
11667                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
11668                                         CHECK_TYPELOAD (klass);
11669                                         mono_class_init (klass);
11670                                         val = mono_type_size (&klass->byval_arg, &ialign);
11671                                 }
11672                                 EMIT_NEW_ICONST (cfg, ins, val);
11673                                 *sp++= ins;
11674                                 ip += 6;
11675                                 break;
11676                         }
11677                         case CEE_REFANYTYPE: {
11678                                 MonoInst *src_var, *src;
11679
11680                                 GSHAREDVT_FAILURE (*ip);
11681
11682                                 CHECK_STACK (1);
11683                                 --sp;
11684
11685                                 // FIXME:
11686                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
11687                                 if (!src_var)
11688                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
11689                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
11690                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
11691                                 *sp++ = ins;
11692                                 ip += 2;
11693                                 break;
11694                         }
11695                         case CEE_READONLY_:
11696                                 readonly = TRUE;
11697                                 ip += 2;
11698                                 break;
11699
11700                         case CEE_UNUSED56:
11701                         case CEE_UNUSED57:
11702                         case CEE_UNUSED70:
11703                         case CEE_UNUSED:
11704                         case CEE_UNUSED99:
11705                                 UNVERIFIED;
11706                                 
11707                         default:
11708                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
11709                                 UNVERIFIED;
11710                         }
11711                         break;
11712                 }
11713                 case CEE_UNUSED58:
11714                 case CEE_UNUSED1:
11715                         UNVERIFIED;
11716
11717                 default:
11718                         g_warning ("opcode 0x%02x not handled", *ip);
11719                         UNVERIFIED;
11720                 }
11721         }
11722         if (start_new_bblock != 1)
11723                 UNVERIFIED;
11724
11725         bblock->cil_length = ip - bblock->cil_code;
11726         if (bblock->next_bb) {
11727                 /* This could already be set because of inlining, #693905 */
11728                 MonoBasicBlock *bb = bblock;
11729
11730                 while (bb->next_bb)
11731                         bb = bb->next_bb;
11732                 bb->next_bb = end_bblock;
11733         } else {
11734                 bblock->next_bb = end_bblock;
11735         }
11736
11737         if (cfg->method == method && cfg->domainvar) {
11738                 MonoInst *store;
11739                 MonoInst *get_domain;
11740
11741                 cfg->cbb = init_localsbb;
11742
11743                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
11744                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
11745                 }
11746                 else {
11747                         get_domain->dreg = alloc_preg (cfg);
11748                         MONO_ADD_INS (cfg->cbb, get_domain);
11749                 }               
11750                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
11751                 MONO_ADD_INS (cfg->cbb, store);
11752         }
11753
11754 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
11755         if (cfg->compile_aot)
11756                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
11757                 mono_get_got_var (cfg);
11758 #endif
11759
11760         if (cfg->method == method && cfg->got_var)
11761                 mono_emit_load_got_addr (cfg);
11762
11763         if (init_locals) {
11764                 MonoInst *store;
11765
11766                 cfg->cbb = init_localsbb;
11767                 cfg->ip = NULL;
11768                 for (i = 0; i < header->num_locals; ++i) {
11769                         MonoType *ptype = header->locals [i];
11770                         int t = ptype->type;
11771                         dreg = cfg->locals [i]->dreg;
11772
11773                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
11774                                 t = mono_class_enum_basetype (ptype->data.klass)->type;
11775                         if (ptype->byref) {
11776                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
11777                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
11778                                 MONO_EMIT_NEW_ICONST (cfg, cfg->locals [i]->dreg, 0);
11779                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
11780                                 MONO_EMIT_NEW_I8CONST (cfg, cfg->locals [i]->dreg, 0);
11781                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
11782                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
11783                                 ins->type = STACK_R8;
11784                                 ins->inst_p0 = (void*)&r8_0;
11785                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
11786                                 MONO_ADD_INS (init_localsbb, ins);
11787                                 EMIT_NEW_LOCSTORE (cfg, store, i, ins);
11788                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
11789                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
11790                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
11791                         } else if (((t == MONO_TYPE_VAR) || (t == MONO_TYPE_MVAR)) && mini_type_var_is_vt (cfg, ptype)) {
11792                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
11793                         } else {
11794                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
11795                         }
11796                 }
11797         }
11798
11799         if (cfg->init_ref_vars && cfg->method == method) {
11800                 /* Emit initialization for ref vars */
11801                 // FIXME: Avoid duplication initialization for IL locals.
11802                 for (i = 0; i < cfg->num_varinfo; ++i) {
11803                         MonoInst *ins = cfg->varinfo [i];
11804
11805                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
11806                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
11807                 }
11808         }
11809
11810         if (seq_points) {
11811                 MonoBasicBlock *bb;
11812
11813                 /*
11814                  * Make seq points at backward branch targets interruptable.
11815                  */
11816                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb)
11817                         if (bb->code && bb->in_count > 1 && bb->code->opcode == OP_SEQ_POINT)
11818                                 bb->code->flags |= MONO_INST_SINGLE_STEP_LOC;
11819         }
11820
11821         /* Add a sequence point for method entry/exit events */
11822         if (seq_points) {
11823                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
11824                 MONO_ADD_INS (init_localsbb, ins);
11825                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
11826                 MONO_ADD_INS (cfg->bb_exit, ins);
11827         }
11828
11829         /*
11830          * Add seq points for IL offsets which have line number info, but wasn't generated a seq point during JITting because
11831          * the code they refer to was dead (#11880).
11832          */
11833         if (sym_seq_points) {
11834                 for (i = 0; i < header->code_size; ++i) {
11835                         if (mono_bitset_test_fast (seq_point_locs, i) && !mono_bitset_test_fast (seq_point_set_locs, i)) {
11836                                 MonoInst *ins;
11837
11838                                 NEW_SEQ_POINT (cfg, ins, i, FALSE);
11839                                 mono_add_seq_point (cfg, NULL, ins, SEQ_POINT_NATIVE_OFFSET_DEAD_CODE);
11840                         }
11841                 }
11842         }
11843
11844         cfg->ip = NULL;
11845
11846         if (cfg->method == method) {
11847                 MonoBasicBlock *bb;
11848                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11849                         bb->region = mono_find_block_region (cfg, bb->real_offset);
11850                         if (cfg->spvars)
11851                                 mono_create_spvar_for_region (cfg, bb->region);
11852                         if (cfg->verbose_level > 2)
11853                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
11854                 }
11855         }
11856
11857         g_slist_free (class_inits);
11858         dont_inline = g_list_remove (dont_inline, method);
11859
11860         if (inline_costs < 0) {
11861                 char *mname;
11862
11863                 /* Method is too large */
11864                 mname = mono_method_full_name (method, TRUE);
11865                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
11866                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
11867                 g_free (mname);
11868                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11869                 mono_basic_block_free (original_bb);
11870                 return -1;
11871         }
11872
11873         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
11874                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
11875
11876         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11877         mono_basic_block_free (original_bb);
11878         return inline_costs;
11879  
11880  exception_exit:
11881         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
11882         goto cleanup;
11883
11884  inline_failure:
11885         goto cleanup;
11886
11887  load_error:
11888         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
11889         goto cleanup;
11890
11891  unverified:
11892         set_exception_type_from_invalid_il (cfg, method, ip);
11893         goto cleanup;
11894
11895  cleanup:
11896         g_slist_free (class_inits);
11897         mono_basic_block_free (original_bb);
11898         dont_inline = g_list_remove (dont_inline, method);
11899         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
11900         return -1;
11901 }
11902
11903 static int
11904 store_membase_reg_to_store_membase_imm (int opcode)
11905 {
11906         switch (opcode) {
11907         case OP_STORE_MEMBASE_REG:
11908                 return OP_STORE_MEMBASE_IMM;
11909         case OP_STOREI1_MEMBASE_REG:
11910                 return OP_STOREI1_MEMBASE_IMM;
11911         case OP_STOREI2_MEMBASE_REG:
11912                 return OP_STOREI2_MEMBASE_IMM;
11913         case OP_STOREI4_MEMBASE_REG:
11914                 return OP_STOREI4_MEMBASE_IMM;
11915         case OP_STOREI8_MEMBASE_REG:
11916                 return OP_STOREI8_MEMBASE_IMM;
11917         default:
11918                 g_assert_not_reached ();
11919         }
11920
11921         return -1;
11922 }               
11923
11924 int
11925 mono_op_to_op_imm (int opcode)
11926 {
11927         switch (opcode) {
11928         case OP_IADD:
11929                 return OP_IADD_IMM;
11930         case OP_ISUB:
11931                 return OP_ISUB_IMM;
11932         case OP_IDIV:
11933                 return OP_IDIV_IMM;
11934         case OP_IDIV_UN:
11935                 return OP_IDIV_UN_IMM;
11936         case OP_IREM:
11937                 return OP_IREM_IMM;
11938         case OP_IREM_UN:
11939                 return OP_IREM_UN_IMM;
11940         case OP_IMUL:
11941                 return OP_IMUL_IMM;
11942         case OP_IAND:
11943                 return OP_IAND_IMM;
11944         case OP_IOR:
11945                 return OP_IOR_IMM;
11946         case OP_IXOR:
11947                 return OP_IXOR_IMM;
11948         case OP_ISHL:
11949                 return OP_ISHL_IMM;
11950         case OP_ISHR:
11951                 return OP_ISHR_IMM;
11952         case OP_ISHR_UN:
11953                 return OP_ISHR_UN_IMM;
11954
11955         case OP_LADD:
11956                 return OP_LADD_IMM;
11957         case OP_LSUB:
11958                 return OP_LSUB_IMM;
11959         case OP_LAND:
11960                 return OP_LAND_IMM;
11961         case OP_LOR:
11962                 return OP_LOR_IMM;
11963         case OP_LXOR:
11964                 return OP_LXOR_IMM;
11965         case OP_LSHL:
11966                 return OP_LSHL_IMM;
11967         case OP_LSHR:
11968                 return OP_LSHR_IMM;
11969         case OP_LSHR_UN:
11970                 return OP_LSHR_UN_IMM;          
11971
11972         case OP_COMPARE:
11973                 return OP_COMPARE_IMM;
11974         case OP_ICOMPARE:
11975                 return OP_ICOMPARE_IMM;
11976         case OP_LCOMPARE:
11977                 return OP_LCOMPARE_IMM;
11978
11979         case OP_STORE_MEMBASE_REG:
11980                 return OP_STORE_MEMBASE_IMM;
11981         case OP_STOREI1_MEMBASE_REG:
11982                 return OP_STOREI1_MEMBASE_IMM;
11983         case OP_STOREI2_MEMBASE_REG:
11984                 return OP_STOREI2_MEMBASE_IMM;
11985         case OP_STOREI4_MEMBASE_REG:
11986                 return OP_STOREI4_MEMBASE_IMM;
11987
11988 #if defined(TARGET_X86) || defined (TARGET_AMD64)
11989         case OP_X86_PUSH:
11990                 return OP_X86_PUSH_IMM;
11991         case OP_X86_COMPARE_MEMBASE_REG:
11992                 return OP_X86_COMPARE_MEMBASE_IMM;
11993 #endif
11994 #if defined(TARGET_AMD64)
11995         case OP_AMD64_ICOMPARE_MEMBASE_REG:
11996                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
11997 #endif
11998         case OP_VOIDCALL_REG:
11999                 return OP_VOIDCALL;
12000         case OP_CALL_REG:
12001                 return OP_CALL;
12002         case OP_LCALL_REG:
12003                 return OP_LCALL;
12004         case OP_FCALL_REG:
12005                 return OP_FCALL;
12006         case OP_LOCALLOC:
12007                 return OP_LOCALLOC_IMM;
12008         }
12009
12010         return -1;
12011 }
12012
12013 static int
12014 ldind_to_load_membase (int opcode)
12015 {
12016         switch (opcode) {
12017         case CEE_LDIND_I1:
12018                 return OP_LOADI1_MEMBASE;
12019         case CEE_LDIND_U1:
12020                 return OP_LOADU1_MEMBASE;
12021         case CEE_LDIND_I2:
12022                 return OP_LOADI2_MEMBASE;
12023         case CEE_LDIND_U2:
12024                 return OP_LOADU2_MEMBASE;
12025         case CEE_LDIND_I4:
12026                 return OP_LOADI4_MEMBASE;
12027         case CEE_LDIND_U4:
12028                 return OP_LOADU4_MEMBASE;
12029         case CEE_LDIND_I:
12030                 return OP_LOAD_MEMBASE;
12031         case CEE_LDIND_REF:
12032                 return OP_LOAD_MEMBASE;
12033         case CEE_LDIND_I8:
12034                 return OP_LOADI8_MEMBASE;
12035         case CEE_LDIND_R4:
12036                 return OP_LOADR4_MEMBASE;
12037         case CEE_LDIND_R8:
12038                 return OP_LOADR8_MEMBASE;
12039         default:
12040                 g_assert_not_reached ();
12041         }
12042
12043         return -1;
12044 }
12045
12046 static int
12047 stind_to_store_membase (int opcode)
12048 {
12049         switch (opcode) {
12050         case CEE_STIND_I1:
12051                 return OP_STOREI1_MEMBASE_REG;
12052         case CEE_STIND_I2:
12053                 return OP_STOREI2_MEMBASE_REG;
12054         case CEE_STIND_I4:
12055                 return OP_STOREI4_MEMBASE_REG;
12056         case CEE_STIND_I:
12057         case CEE_STIND_REF:
12058                 return OP_STORE_MEMBASE_REG;
12059         case CEE_STIND_I8:
12060                 return OP_STOREI8_MEMBASE_REG;
12061         case CEE_STIND_R4:
12062                 return OP_STORER4_MEMBASE_REG;
12063         case CEE_STIND_R8:
12064                 return OP_STORER8_MEMBASE_REG;
12065         default:
12066                 g_assert_not_reached ();
12067         }
12068
12069         return -1;
12070 }
12071
12072 int
12073 mono_load_membase_to_load_mem (int opcode)
12074 {
12075         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
12076 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12077         switch (opcode) {
12078         case OP_LOAD_MEMBASE:
12079                 return OP_LOAD_MEM;
12080         case OP_LOADU1_MEMBASE:
12081                 return OP_LOADU1_MEM;
12082         case OP_LOADU2_MEMBASE:
12083                 return OP_LOADU2_MEM;
12084         case OP_LOADI4_MEMBASE:
12085                 return OP_LOADI4_MEM;
12086         case OP_LOADU4_MEMBASE:
12087                 return OP_LOADU4_MEM;
12088 #if SIZEOF_REGISTER == 8
12089         case OP_LOADI8_MEMBASE:
12090                 return OP_LOADI8_MEM;
12091 #endif
12092         }
12093 #endif
12094
12095         return -1;
12096 }
12097
12098 static inline int
12099 op_to_op_dest_membase (int store_opcode, int opcode)
12100 {
12101 #if defined(TARGET_X86)
12102         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
12103                 return -1;
12104
12105         switch (opcode) {
12106         case OP_IADD:
12107                 return OP_X86_ADD_MEMBASE_REG;
12108         case OP_ISUB:
12109                 return OP_X86_SUB_MEMBASE_REG;
12110         case OP_IAND:
12111                 return OP_X86_AND_MEMBASE_REG;
12112         case OP_IOR:
12113                 return OP_X86_OR_MEMBASE_REG;
12114         case OP_IXOR:
12115                 return OP_X86_XOR_MEMBASE_REG;
12116         case OP_ADD_IMM:
12117         case OP_IADD_IMM:
12118                 return OP_X86_ADD_MEMBASE_IMM;
12119         case OP_SUB_IMM:
12120         case OP_ISUB_IMM:
12121                 return OP_X86_SUB_MEMBASE_IMM;
12122         case OP_AND_IMM:
12123         case OP_IAND_IMM:
12124                 return OP_X86_AND_MEMBASE_IMM;
12125         case OP_OR_IMM:
12126         case OP_IOR_IMM:
12127                 return OP_X86_OR_MEMBASE_IMM;
12128         case OP_XOR_IMM:
12129         case OP_IXOR_IMM:
12130                 return OP_X86_XOR_MEMBASE_IMM;
12131         case OP_MOVE:
12132                 return OP_NOP;
12133         }
12134 #endif
12135
12136 #if defined(TARGET_AMD64)
12137         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
12138                 return -1;
12139
12140         switch (opcode) {
12141         case OP_IADD:
12142                 return OP_X86_ADD_MEMBASE_REG;
12143         case OP_ISUB:
12144                 return OP_X86_SUB_MEMBASE_REG;
12145         case OP_IAND:
12146                 return OP_X86_AND_MEMBASE_REG;
12147         case OP_IOR:
12148                 return OP_X86_OR_MEMBASE_REG;
12149         case OP_IXOR:
12150                 return OP_X86_XOR_MEMBASE_REG;
12151         case OP_IADD_IMM:
12152                 return OP_X86_ADD_MEMBASE_IMM;
12153         case OP_ISUB_IMM:
12154                 return OP_X86_SUB_MEMBASE_IMM;
12155         case OP_IAND_IMM:
12156                 return OP_X86_AND_MEMBASE_IMM;
12157         case OP_IOR_IMM:
12158                 return OP_X86_OR_MEMBASE_IMM;
12159         case OP_IXOR_IMM:
12160                 return OP_X86_XOR_MEMBASE_IMM;
12161         case OP_LADD:
12162                 return OP_AMD64_ADD_MEMBASE_REG;
12163         case OP_LSUB:
12164                 return OP_AMD64_SUB_MEMBASE_REG;
12165         case OP_LAND:
12166                 return OP_AMD64_AND_MEMBASE_REG;
12167         case OP_LOR:
12168                 return OP_AMD64_OR_MEMBASE_REG;
12169         case OP_LXOR:
12170                 return OP_AMD64_XOR_MEMBASE_REG;
12171         case OP_ADD_IMM:
12172         case OP_LADD_IMM:
12173                 return OP_AMD64_ADD_MEMBASE_IMM;
12174         case OP_SUB_IMM:
12175         case OP_LSUB_IMM:
12176                 return OP_AMD64_SUB_MEMBASE_IMM;
12177         case OP_AND_IMM:
12178         case OP_LAND_IMM:
12179                 return OP_AMD64_AND_MEMBASE_IMM;
12180         case OP_OR_IMM:
12181         case OP_LOR_IMM:
12182                 return OP_AMD64_OR_MEMBASE_IMM;
12183         case OP_XOR_IMM:
12184         case OP_LXOR_IMM:
12185                 return OP_AMD64_XOR_MEMBASE_IMM;
12186         case OP_MOVE:
12187                 return OP_NOP;
12188         }
12189 #endif
12190
12191         return -1;
12192 }
12193
12194 static inline int
12195 op_to_op_store_membase (int store_opcode, int opcode)
12196 {
12197 #if defined(TARGET_X86) || defined(TARGET_AMD64)
12198         switch (opcode) {
12199         case OP_ICEQ:
12200                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12201                         return OP_X86_SETEQ_MEMBASE;
12202         case OP_CNE:
12203                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
12204                         return OP_X86_SETNE_MEMBASE;
12205         }
12206 #endif
12207
12208         return -1;
12209 }
12210
12211 static inline int
12212 op_to_op_src1_membase (int load_opcode, int opcode)
12213 {
12214 #ifdef TARGET_X86
12215         /* FIXME: This has sign extension issues */
12216         /*
12217         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12218                 return OP_X86_COMPARE_MEMBASE8_IMM;
12219         */
12220
12221         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12222                 return -1;
12223
12224         switch (opcode) {
12225         case OP_X86_PUSH:
12226                 return OP_X86_PUSH_MEMBASE;
12227         case OP_COMPARE_IMM:
12228         case OP_ICOMPARE_IMM:
12229                 return OP_X86_COMPARE_MEMBASE_IMM;
12230         case OP_COMPARE:
12231         case OP_ICOMPARE:
12232                 return OP_X86_COMPARE_MEMBASE_REG;
12233         }
12234 #endif
12235
12236 #ifdef TARGET_AMD64
12237         /* FIXME: This has sign extension issues */
12238         /*
12239         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
12240                 return OP_X86_COMPARE_MEMBASE8_IMM;
12241         */
12242
12243         switch (opcode) {
12244         case OP_X86_PUSH:
12245 #ifdef __mono_ilp32__
12246                 if (load_opcode == OP_LOADI8_MEMBASE)
12247 #else
12248                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12249 #endif
12250                         return OP_X86_PUSH_MEMBASE;
12251                 break;
12252                 /* FIXME: This only works for 32 bit immediates
12253         case OP_COMPARE_IMM:
12254         case OP_LCOMPARE_IMM:
12255                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12256                         return OP_AMD64_COMPARE_MEMBASE_IMM;
12257                 */
12258         case OP_ICOMPARE_IMM:
12259                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12260                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
12261                 break;
12262         case OP_COMPARE:
12263         case OP_LCOMPARE:
12264 #ifdef __mono_ilp32__
12265                 if (load_opcode == OP_LOAD_MEMBASE)
12266                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12267                 if (load_opcode == OP_LOADI8_MEMBASE)
12268 #else
12269                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
12270 #endif
12271                         return OP_AMD64_COMPARE_MEMBASE_REG;
12272                 break;
12273         case OP_ICOMPARE:
12274                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
12275                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
12276                 break;
12277         }
12278 #endif
12279
12280         return -1;
12281 }
12282
12283 static inline int
12284 op_to_op_src2_membase (int load_opcode, int opcode)
12285 {
12286 #ifdef TARGET_X86
12287         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
12288                 return -1;
12289         
12290         switch (opcode) {
12291         case OP_COMPARE:
12292         case OP_ICOMPARE:
12293                 return OP_X86_COMPARE_REG_MEMBASE;
12294         case OP_IADD:
12295                 return OP_X86_ADD_REG_MEMBASE;
12296         case OP_ISUB:
12297                 return OP_X86_SUB_REG_MEMBASE;
12298         case OP_IAND:
12299                 return OP_X86_AND_REG_MEMBASE;
12300         case OP_IOR:
12301                 return OP_X86_OR_REG_MEMBASE;
12302         case OP_IXOR:
12303                 return OP_X86_XOR_REG_MEMBASE;
12304         }
12305 #endif
12306
12307 #ifdef TARGET_AMD64
12308 #ifdef __mono_ilp32__
12309         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE) ) {
12310 #else
12311         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
12312 #endif
12313                 switch (opcode) {
12314                 case OP_ICOMPARE:
12315                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
12316                 case OP_IADD:
12317                         return OP_X86_ADD_REG_MEMBASE;
12318                 case OP_ISUB:
12319                         return OP_X86_SUB_REG_MEMBASE;
12320                 case OP_IAND:
12321                         return OP_X86_AND_REG_MEMBASE;
12322                 case OP_IOR:
12323                         return OP_X86_OR_REG_MEMBASE;
12324                 case OP_IXOR:
12325                         return OP_X86_XOR_REG_MEMBASE;
12326                 }
12327 #ifdef __mono_ilp32__
12328         } else if (load_opcode == OP_LOADI8_MEMBASE) {
12329 #else
12330         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
12331 #endif
12332                 switch (opcode) {
12333                 case OP_COMPARE:
12334                 case OP_LCOMPARE:
12335                         return OP_AMD64_COMPARE_REG_MEMBASE;
12336                 case OP_LADD:
12337                         return OP_AMD64_ADD_REG_MEMBASE;
12338                 case OP_LSUB:
12339                         return OP_AMD64_SUB_REG_MEMBASE;
12340                 case OP_LAND:
12341                         return OP_AMD64_AND_REG_MEMBASE;
12342                 case OP_LOR:
12343                         return OP_AMD64_OR_REG_MEMBASE;
12344                 case OP_LXOR:
12345                         return OP_AMD64_XOR_REG_MEMBASE;
12346                 }
12347         }
12348 #endif
12349
12350         return -1;
12351 }
12352
12353 int
12354 mono_op_to_op_imm_noemul (int opcode)
12355 {
12356         switch (opcode) {
12357 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
12358         case OP_LSHR:
12359         case OP_LSHL:
12360         case OP_LSHR_UN:
12361                 return -1;
12362 #endif
12363 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
12364         case OP_IDIV:
12365         case OP_IDIV_UN:
12366         case OP_IREM:
12367         case OP_IREM_UN:
12368                 return -1;
12369 #endif
12370 #if defined(MONO_ARCH_EMULATE_MUL_DIV)
12371         case OP_IMUL:
12372                 return -1;
12373 #endif
12374         default:
12375                 return mono_op_to_op_imm (opcode);
12376         }
12377 }
12378
12379 /**
12380  * mono_handle_global_vregs:
12381  *
12382  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
12383  * for them.
12384  */
12385 void
12386 mono_handle_global_vregs (MonoCompile *cfg)
12387 {
12388         gint32 *vreg_to_bb;
12389         MonoBasicBlock *bb;
12390         int i, pos;
12391
12392         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
12393
12394 #ifdef MONO_ARCH_SIMD_INTRINSICS
12395         if (cfg->uses_simd_intrinsics)
12396                 mono_simd_simplify_indirection (cfg);
12397 #endif
12398
12399         /* Find local vregs used in more than one bb */
12400         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12401                 MonoInst *ins = bb->code;       
12402                 int block_num = bb->block_num;
12403
12404                 if (cfg->verbose_level > 2)
12405                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
12406
12407                 cfg->cbb = bb;
12408                 for (; ins; ins = ins->next) {
12409                         const char *spec = INS_INFO (ins->opcode);
12410                         int regtype = 0, regindex;
12411                         gint32 prev_bb;
12412
12413                         if (G_UNLIKELY (cfg->verbose_level > 2))
12414                                 mono_print_ins (ins);
12415
12416                         g_assert (ins->opcode >= MONO_CEE_LAST);
12417
12418                         for (regindex = 0; regindex < 4; regindex ++) {
12419                                 int vreg = 0;
12420
12421                                 if (regindex == 0) {
12422                                         regtype = spec [MONO_INST_DEST];
12423                                         if (regtype == ' ')
12424                                                 continue;
12425                                         vreg = ins->dreg;
12426                                 } else if (regindex == 1) {
12427                                         regtype = spec [MONO_INST_SRC1];
12428                                         if (regtype == ' ')
12429                                                 continue;
12430                                         vreg = ins->sreg1;
12431                                 } else if (regindex == 2) {
12432                                         regtype = spec [MONO_INST_SRC2];
12433                                         if (regtype == ' ')
12434                                                 continue;
12435                                         vreg = ins->sreg2;
12436                                 } else if (regindex == 3) {
12437                                         regtype = spec [MONO_INST_SRC3];
12438                                         if (regtype == ' ')
12439                                                 continue;
12440                                         vreg = ins->sreg3;
12441                                 }
12442
12443 #if SIZEOF_REGISTER == 4
12444                                 /* In the LLVM case, the long opcodes are not decomposed */
12445                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
12446                                         /*
12447                                          * Since some instructions reference the original long vreg,
12448                                          * and some reference the two component vregs, it is quite hard
12449                                          * to determine when it needs to be global. So be conservative.
12450                                          */
12451                                         if (!get_vreg_to_inst (cfg, vreg)) {
12452                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12453
12454                                                 if (cfg->verbose_level > 2)
12455                                                         printf ("LONG VREG R%d made global.\n", vreg);
12456                                         }
12457
12458                                         /*
12459                                          * Make the component vregs volatile since the optimizations can
12460                                          * get confused otherwise.
12461                                          */
12462                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
12463                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
12464                                 }
12465 #endif
12466
12467                                 g_assert (vreg != -1);
12468
12469                                 prev_bb = vreg_to_bb [vreg];
12470                                 if (prev_bb == 0) {
12471                                         /* 0 is a valid block num */
12472                                         vreg_to_bb [vreg] = block_num + 1;
12473                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
12474                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
12475                                                 continue;
12476
12477                                         if (!get_vreg_to_inst (cfg, vreg)) {
12478                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12479                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
12480
12481                                                 switch (regtype) {
12482                                                 case 'i':
12483                                                         if (vreg_is_ref (cfg, vreg))
12484                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL, vreg);
12485                                                         else
12486                                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
12487                                                         break;
12488                                                 case 'l':
12489                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
12490                                                         break;
12491                                                 case 'f':
12492                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
12493                                                         break;
12494                                                 case 'v':
12495                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
12496                                                         break;
12497                                                 default:
12498                                                         g_assert_not_reached ();
12499                                                 }
12500                                         }
12501
12502                                         /* Flag as having been used in more than one bb */
12503                                         vreg_to_bb [vreg] = -1;
12504                                 }
12505                         }
12506                 }
12507         }
12508
12509         /* If a variable is used in only one bblock, convert it into a local vreg */
12510         for (i = 0; i < cfg->num_varinfo; i++) {
12511                 MonoInst *var = cfg->varinfo [i];
12512                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
12513
12514                 switch (var->type) {
12515                 case STACK_I4:
12516                 case STACK_OBJ:
12517                 case STACK_PTR:
12518                 case STACK_MP:
12519                 case STACK_VTYPE:
12520 #if SIZEOF_REGISTER == 8
12521                 case STACK_I8:
12522 #endif
12523 #if !defined(TARGET_X86)
12524                 /* Enabling this screws up the fp stack on x86 */
12525                 case STACK_R8:
12526 #endif
12527                         if (mono_arch_is_soft_float ())
12528                                 break;
12529
12530                         /* Arguments are implicitly global */
12531                         /* Putting R4 vars into registers doesn't work currently */
12532                         /* The gsharedvt vars are implicitly referenced by ldaddr opcodes, but those opcodes are only generated later */
12533                         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) {
12534                                 /* 
12535                                  * Make that the variable's liveness interval doesn't contain a call, since
12536                                  * that would cause the lvreg to be spilled, making the whole optimization
12537                                  * useless.
12538                                  */
12539                                 /* This is too slow for JIT compilation */
12540 #if 0
12541                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
12542                                         MonoInst *ins;
12543                                         int def_index, call_index, ins_index;
12544                                         gboolean spilled = FALSE;
12545
12546                                         def_index = -1;
12547                                         call_index = -1;
12548                                         ins_index = 0;
12549                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
12550                                                 const char *spec = INS_INFO (ins->opcode);
12551
12552                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
12553                                                         def_index = ins_index;
12554
12555                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
12556                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
12557                                                         if (call_index > def_index) {
12558                                                                 spilled = TRUE;
12559                                                                 break;
12560                                                         }
12561                                                 }
12562
12563                                                 if (MONO_IS_CALL (ins))
12564                                                         call_index = ins_index;
12565
12566                                                 ins_index ++;
12567                                         }
12568
12569                                         if (spilled)
12570                                                 break;
12571                                 }
12572 #endif
12573
12574                                 if (G_UNLIKELY (cfg->verbose_level > 2))
12575                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
12576                                 var->flags |= MONO_INST_IS_DEAD;
12577                                 cfg->vreg_to_inst [var->dreg] = NULL;
12578                         }
12579                         break;
12580                 }
12581         }
12582
12583         /* 
12584          * Compress the varinfo and vars tables so the liveness computation is faster and
12585          * takes up less space.
12586          */
12587         pos = 0;
12588         for (i = 0; i < cfg->num_varinfo; ++i) {
12589                 MonoInst *var = cfg->varinfo [i];
12590                 if (pos < i && cfg->locals_start == i)
12591                         cfg->locals_start = pos;
12592                 if (!(var->flags & MONO_INST_IS_DEAD)) {
12593                         if (pos < i) {
12594                                 cfg->varinfo [pos] = cfg->varinfo [i];
12595                                 cfg->varinfo [pos]->inst_c0 = pos;
12596                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
12597                                 cfg->vars [pos].idx = pos;
12598 #if SIZEOF_REGISTER == 4
12599                                 if (cfg->varinfo [pos]->type == STACK_I8) {
12600                                         /* Modify the two component vars too */
12601                                         MonoInst *var1;
12602
12603                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
12604                                         var1->inst_c0 = pos;
12605                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
12606                                         var1->inst_c0 = pos;
12607                                 }
12608 #endif
12609                         }
12610                         pos ++;
12611                 }
12612         }
12613         cfg->num_varinfo = pos;
12614         if (cfg->locals_start > cfg->num_varinfo)
12615                 cfg->locals_start = cfg->num_varinfo;
12616 }
12617
12618 /**
12619  * mono_spill_global_vars:
12620  *
12621  *   Generate spill code for variables which are not allocated to registers, 
12622  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
12623  * code is generated which could be optimized by the local optimization passes.
12624  */
12625 void
12626 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
12627 {
12628         MonoBasicBlock *bb;
12629         char spec2 [16];
12630         int orig_next_vreg;
12631         guint32 *vreg_to_lvreg;
12632         guint32 *lvregs;
12633         guint32 i, lvregs_len;
12634         gboolean dest_has_lvreg = FALSE;
12635         guint32 stacktypes [128];
12636         MonoInst **live_range_start, **live_range_end;
12637         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
12638         int *gsharedvt_vreg_to_idx = NULL;
12639
12640         *need_local_opts = FALSE;
12641
12642         memset (spec2, 0, sizeof (spec2));
12643
12644         /* FIXME: Move this function to mini.c */
12645         stacktypes ['i'] = STACK_PTR;
12646         stacktypes ['l'] = STACK_I8;
12647         stacktypes ['f'] = STACK_R8;
12648 #ifdef MONO_ARCH_SIMD_INTRINSICS
12649         stacktypes ['x'] = STACK_VTYPE;
12650 #endif
12651
12652 #if SIZEOF_REGISTER == 4
12653         /* Create MonoInsts for longs */
12654         for (i = 0; i < cfg->num_varinfo; i++) {
12655                 MonoInst *ins = cfg->varinfo [i];
12656
12657                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
12658                         switch (ins->type) {
12659                         case STACK_R8:
12660                         case STACK_I8: {
12661                                 MonoInst *tree;
12662
12663                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
12664                                         break;
12665
12666                                 g_assert (ins->opcode == OP_REGOFFSET);
12667
12668                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
12669                                 g_assert (tree);
12670                                 tree->opcode = OP_REGOFFSET;
12671                                 tree->inst_basereg = ins->inst_basereg;
12672                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
12673
12674                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
12675                                 g_assert (tree);
12676                                 tree->opcode = OP_REGOFFSET;
12677                                 tree->inst_basereg = ins->inst_basereg;
12678                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
12679                                 break;
12680                         }
12681                         default:
12682                                 break;
12683                         }
12684                 }
12685         }
12686 #endif
12687
12688         if (cfg->compute_gc_maps) {
12689                 /* registers need liveness info even for !non refs */
12690                 for (i = 0; i < cfg->num_varinfo; i++) {
12691                         MonoInst *ins = cfg->varinfo [i];
12692
12693                         if (ins->opcode == OP_REGVAR)
12694                                 ins->flags |= MONO_INST_GC_TRACK;
12695                 }
12696         }
12697
12698         if (cfg->gsharedvt) {
12699                 gsharedvt_vreg_to_idx = g_new0 (int, cfg->next_vreg);
12700
12701                 for (i = 0; i < cfg->num_varinfo; ++i) {
12702                         MonoInst *ins = cfg->varinfo [i];
12703                         int idx;
12704
12705                         if (mini_is_gsharedvt_variable_type (cfg, ins->inst_vtype)) {
12706                                 if (i >= cfg->locals_start) {
12707                                         /* Local */
12708                                         idx = get_gsharedvt_info_slot (cfg, ins->inst_vtype, MONO_RGCTX_INFO_LOCAL_OFFSET);
12709                                         gsharedvt_vreg_to_idx [ins->dreg] = idx + 1;
12710                                         ins->opcode = OP_GSHAREDVT_LOCAL;
12711                                         ins->inst_imm = idx;
12712                                 } else {
12713                                         /* Arg */
12714                                         gsharedvt_vreg_to_idx [ins->dreg] = -1;
12715                                         ins->opcode = OP_GSHAREDVT_ARG_REGOFFSET;
12716                                 }
12717                         }
12718                 }
12719         }
12720                 
12721         /* FIXME: widening and truncation */
12722
12723         /*
12724          * As an optimization, when a variable allocated to the stack is first loaded into 
12725          * an lvreg, we will remember the lvreg and use it the next time instead of loading
12726          * the variable again.
12727          */
12728         orig_next_vreg = cfg->next_vreg;
12729         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
12730         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
12731         lvregs_len = 0;
12732
12733         /* 
12734          * These arrays contain the first and last instructions accessing a given
12735          * variable.
12736          * Since we emit bblocks in the same order we process them here, and we
12737          * don't split live ranges, these will precisely describe the live range of
12738          * the variable, i.e. the instruction range where a valid value can be found
12739          * in the variables location.
12740          * The live range is computed using the liveness info computed by the liveness pass.
12741          * We can't use vmv->range, since that is an abstract live range, and we need
12742          * one which is instruction precise.
12743          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
12744          */
12745         /* FIXME: Only do this if debugging info is requested */
12746         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
12747         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
12748         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
12749         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
12750         
12751         /* Add spill loads/stores */
12752         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
12753                 MonoInst *ins;
12754
12755                 if (cfg->verbose_level > 2)
12756                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
12757
12758                 /* Clear vreg_to_lvreg array */
12759                 for (i = 0; i < lvregs_len; i++)
12760                         vreg_to_lvreg [lvregs [i]] = 0;
12761                 lvregs_len = 0;
12762
12763                 cfg->cbb = bb;
12764                 MONO_BB_FOR_EACH_INS (bb, ins) {
12765                         const char *spec = INS_INFO (ins->opcode);
12766                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
12767                         gboolean store, no_lvreg;
12768                         int sregs [MONO_MAX_SRC_REGS];
12769
12770                         if (G_UNLIKELY (cfg->verbose_level > 2))
12771                                 mono_print_ins (ins);
12772
12773                         if (ins->opcode == OP_NOP)
12774                                 continue;
12775
12776                         /* 
12777                          * We handle LDADDR here as well, since it can only be decomposed
12778                          * when variable addresses are known.
12779                          */
12780                         if (ins->opcode == OP_LDADDR) {
12781                                 MonoInst *var = ins->inst_p0;
12782
12783                                 if (var->opcode == OP_VTARG_ADDR) {
12784                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
12785                                         MonoInst *vtaddr = var->inst_left;
12786                                         if (vtaddr->opcode == OP_REGVAR) {
12787                                                 ins->opcode = OP_MOVE;
12788                                                 ins->sreg1 = vtaddr->dreg;
12789                                         }
12790                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
12791                                                 ins->opcode = OP_LOAD_MEMBASE;
12792                                                 ins->inst_basereg = vtaddr->inst_basereg;
12793                                                 ins->inst_offset = vtaddr->inst_offset;
12794                                         } else
12795                                                 NOT_IMPLEMENTED;
12796                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg] < 0) {
12797                                         /* gsharedvt arg passed by ref */
12798                                         g_assert (var->opcode == OP_GSHAREDVT_ARG_REGOFFSET);
12799
12800                                         ins->opcode = OP_LOAD_MEMBASE;
12801                                         ins->inst_basereg = var->inst_basereg;
12802                                         ins->inst_offset = var->inst_offset;
12803                                 } else if (cfg->gsharedvt && gsharedvt_vreg_to_idx [var->dreg]) {
12804                                         MonoInst *load, *load2, *load3;
12805                                         int idx = gsharedvt_vreg_to_idx [var->dreg] - 1;
12806                                         int reg1, reg2, reg3;
12807                                         MonoInst *info_var = cfg->gsharedvt_info_var;
12808                                         MonoInst *locals_var = cfg->gsharedvt_locals_var;
12809
12810                                         /*
12811                                          * gsharedvt local.
12812                                          * Compute the address of the local as gsharedvt_locals_var + gsharedvt_info_var->locals_offsets [idx].
12813                                          */
12814
12815                                         g_assert (var->opcode == OP_GSHAREDVT_LOCAL);
12816
12817                                         g_assert (info_var);
12818                                         g_assert (locals_var);
12819
12820                                         /* Mark the instruction used to compute the locals var as used */
12821                                         cfg->gsharedvt_locals_var_ins = NULL;
12822
12823                                         /* Load the offset */
12824                                         if (info_var->opcode == OP_REGOFFSET) {
12825                                                 reg1 = alloc_ireg (cfg);
12826                                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, reg1, info_var->inst_basereg, info_var->inst_offset);
12827                                         } else if (info_var->opcode == OP_REGVAR) {
12828                                                 load = NULL;
12829                                                 reg1 = info_var->dreg;
12830                                         } else {
12831                                                 g_assert_not_reached ();
12832                                         }
12833                                         reg2 = alloc_ireg (cfg);
12834                                         NEW_LOAD_MEMBASE (cfg, load2, OP_LOADI4_MEMBASE, reg2, reg1, G_STRUCT_OFFSET (MonoGSharedVtMethodRuntimeInfo, entries) + (idx * sizeof (gpointer)));
12835                                         /* Load the locals area address */
12836                                         reg3 = alloc_ireg (cfg);
12837                                         if (locals_var->opcode == OP_REGOFFSET) {
12838                                                 NEW_LOAD_MEMBASE (cfg, load3, OP_LOAD_MEMBASE, reg3, locals_var->inst_basereg, locals_var->inst_offset);
12839                                         } else if (locals_var->opcode == OP_REGVAR) {
12840                                                 NEW_UNALU (cfg, load3, OP_MOVE, reg3, locals_var->dreg);
12841                                         } else {
12842                                                 g_assert_not_reached ();
12843                                         }
12844                                         /* Compute the address */
12845                                         ins->opcode = OP_PADD;
12846                                         ins->sreg1 = reg3;
12847                                         ins->sreg2 = reg2;
12848
12849                                         mono_bblock_insert_before_ins (bb, ins, load3);
12850                                         mono_bblock_insert_before_ins (bb, load3, load2);
12851                                         if (load)
12852                                                 mono_bblock_insert_before_ins (bb, load2, load);
12853                                 } else {
12854                                         g_assert (var->opcode == OP_REGOFFSET);
12855
12856                                         ins->opcode = OP_ADD_IMM;
12857                                         ins->sreg1 = var->inst_basereg;
12858                                         ins->inst_imm = var->inst_offset;
12859                                 }
12860
12861                                 *need_local_opts = TRUE;
12862                                 spec = INS_INFO (ins->opcode);
12863                         }
12864
12865                         if (ins->opcode < MONO_CEE_LAST) {
12866                                 mono_print_ins (ins);
12867                                 g_assert_not_reached ();
12868                         }
12869
12870                         /*
12871                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
12872                          * src register.
12873                          * FIXME:
12874                          */
12875                         if (MONO_IS_STORE_MEMBASE (ins)) {
12876                                 tmp_reg = ins->dreg;
12877                                 ins->dreg = ins->sreg2;
12878                                 ins->sreg2 = tmp_reg;
12879                                 store = TRUE;
12880
12881                                 spec2 [MONO_INST_DEST] = ' ';
12882                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
12883                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
12884                                 spec2 [MONO_INST_SRC3] = ' ';
12885                                 spec = spec2;
12886                         } else if (MONO_IS_STORE_MEMINDEX (ins))
12887                                 g_assert_not_reached ();
12888                         else
12889                                 store = FALSE;
12890                         no_lvreg = FALSE;
12891
12892                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
12893                                 printf ("\t %.3s %d", spec, ins->dreg);
12894                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
12895                                 for (srcindex = 0; srcindex < num_sregs; ++srcindex)
12896                                         printf (" %d", sregs [srcindex]);
12897                                 printf ("\n");
12898                         }
12899
12900                         /***************/
12901                         /*    DREG     */
12902                         /***************/
12903                         regtype = spec [MONO_INST_DEST];
12904                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
12905                         prev_dreg = -1;
12906
12907                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
12908                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
12909                                 MonoInst *store_ins;
12910                                 int store_opcode;
12911                                 MonoInst *def_ins = ins;
12912                                 int dreg = ins->dreg; /* The original vreg */
12913
12914                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
12915
12916                                 if (var->opcode == OP_REGVAR) {
12917                                         ins->dreg = var->dreg;
12918                                 } 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)) {
12919                                         /* 
12920                                          * Instead of emitting a load+store, use a _membase opcode.
12921                                          */
12922                                         g_assert (var->opcode == OP_REGOFFSET);
12923                                         if (ins->opcode == OP_MOVE) {
12924                                                 NULLIFY_INS (ins);
12925                                                 def_ins = NULL;
12926                                         } else {
12927                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
12928                                                 ins->inst_basereg = var->inst_basereg;
12929                                                 ins->inst_offset = var->inst_offset;
12930                                                 ins->dreg = -1;
12931                                         }
12932                                         spec = INS_INFO (ins->opcode);
12933                                 } else {
12934                                         guint32 lvreg;
12935
12936                                         g_assert (var->opcode == OP_REGOFFSET);
12937
12938                                         prev_dreg = ins->dreg;
12939
12940                                         /* Invalidate any previous lvreg for this vreg */
12941                                         vreg_to_lvreg [ins->dreg] = 0;
12942
12943                                         lvreg = 0;
12944
12945                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
12946                                                 regtype = 'l';
12947                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
12948                                         }
12949
12950                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
12951
12952 #if SIZEOF_REGISTER != 8
12953                                         if (regtype == 'l') {
12954                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
12955                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
12956                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
12957                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
12958                                                 def_ins = store_ins;
12959                                         }
12960                                         else
12961 #endif
12962                                         {
12963                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
12964
12965                                                 /* Try to fuse the store into the instruction itself */
12966                                                 /* FIXME: Add more instructions */
12967                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
12968                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
12969                                                         ins->inst_imm = ins->inst_c0;
12970                                                         ins->inst_destbasereg = var->inst_basereg;
12971                                                         ins->inst_offset = var->inst_offset;
12972                                                         spec = INS_INFO (ins->opcode);
12973                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
12974                                                         ins->opcode = store_opcode;
12975                                                         ins->inst_destbasereg = var->inst_basereg;
12976                                                         ins->inst_offset = var->inst_offset;
12977
12978                                                         no_lvreg = TRUE;
12979
12980                                                         tmp_reg = ins->dreg;
12981                                                         ins->dreg = ins->sreg2;
12982                                                         ins->sreg2 = tmp_reg;
12983                                                         store = TRUE;
12984
12985                                                         spec2 [MONO_INST_DEST] = ' ';
12986                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
12987                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
12988                                                         spec2 [MONO_INST_SRC3] = ' ';
12989                                                         spec = spec2;
12990                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
12991                                                         // FIXME: The backends expect the base reg to be in inst_basereg
12992                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
12993                                                         ins->dreg = -1;
12994                                                         ins->inst_basereg = var->inst_basereg;
12995                                                         ins->inst_offset = var->inst_offset;
12996                                                         spec = INS_INFO (ins->opcode);
12997                                                 } else {
12998                                                         /* printf ("INS: "); mono_print_ins (ins); */
12999                                                         /* Create a store instruction */
13000                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
13001
13002                                                         /* Insert it after the instruction */
13003                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
13004
13005                                                         def_ins = store_ins;
13006
13007                                                         /* 
13008                                                          * We can't assign ins->dreg to var->dreg here, since the
13009                                                          * sregs could use it. So set a flag, and do it after
13010                                                          * the sregs.
13011                                                          */
13012                                                         if ((!MONO_ARCH_USE_FPSTACK || ((store_opcode != OP_STORER8_MEMBASE_REG) && (store_opcode != OP_STORER4_MEMBASE_REG))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)))
13013                                                                 dest_has_lvreg = TRUE;
13014                                                 }
13015                                         }
13016                                 }
13017
13018                                 if (def_ins && !live_range_start [dreg]) {
13019                                         live_range_start [dreg] = def_ins;
13020                                         live_range_start_bb [dreg] = bb;
13021                                 }
13022
13023                                 if (cfg->compute_gc_maps && def_ins && (var->flags & MONO_INST_GC_TRACK)) {
13024                                         MonoInst *tmp;
13025
13026                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_DEF);
13027                                         tmp->inst_c1 = dreg;
13028                                         mono_bblock_insert_after_ins (bb, def_ins, tmp);
13029                                 }
13030                         }
13031
13032                         /************/
13033                         /*  SREGS   */
13034                         /************/
13035                         num_sregs = mono_inst_get_src_registers (ins, sregs);
13036                         for (srcindex = 0; srcindex < 3; ++srcindex) {
13037                                 regtype = spec [MONO_INST_SRC1 + srcindex];
13038                                 sreg = sregs [srcindex];
13039
13040                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
13041                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
13042                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
13043                                         MonoInst *use_ins = ins;
13044                                         MonoInst *load_ins;
13045                                         guint32 load_opcode;
13046
13047                                         if (var->opcode == OP_REGVAR) {
13048                                                 sregs [srcindex] = var->dreg;
13049                                                 //mono_inst_set_src_registers (ins, sregs);
13050                                                 live_range_end [sreg] = use_ins;
13051                                                 live_range_end_bb [sreg] = bb;
13052
13053                                                 if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13054                                                         MonoInst *tmp;
13055
13056                                                         MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13057                                                         /* var->dreg is a hreg */
13058                                                         tmp->inst_c1 = sreg;
13059                                                         mono_bblock_insert_after_ins (bb, ins, tmp);
13060                                                 }
13061
13062                                                 continue;
13063                                         }
13064
13065                                         g_assert (var->opcode == OP_REGOFFSET);
13066                                                 
13067                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
13068
13069                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
13070
13071                                         if (vreg_to_lvreg [sreg]) {
13072                                                 g_assert (vreg_to_lvreg [sreg] != -1);
13073
13074                                                 /* The variable is already loaded to an lvreg */
13075                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
13076                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
13077                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
13078                                                 //mono_inst_set_src_registers (ins, sregs);
13079                                                 continue;
13080                                         }
13081
13082                                         /* Try to fuse the load into the instruction */
13083                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
13084                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
13085                                                 sregs [0] = var->inst_basereg;
13086                                                 //mono_inst_set_src_registers (ins, sregs);
13087                                                 ins->inst_offset = var->inst_offset;
13088                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
13089                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
13090                                                 sregs [1] = var->inst_basereg;
13091                                                 //mono_inst_set_src_registers (ins, sregs);
13092                                                 ins->inst_offset = var->inst_offset;
13093                                         } else {
13094                                                 if (MONO_IS_REAL_MOVE (ins)) {
13095                                                         ins->opcode = OP_NOP;
13096                                                         sreg = ins->dreg;
13097                                                 } else {
13098                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
13099
13100                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
13101
13102                                                         if ((!MONO_ARCH_USE_FPSTACK || ((load_opcode != OP_LOADR8_MEMBASE) && (load_opcode != OP_LOADR4_MEMBASE))) && !((var)->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT)) && !no_lvreg) {
13103                                                                 if (var->dreg == prev_dreg) {
13104                                                                         /*
13105                                                                          * sreg refers to the value loaded by the load
13106                                                                          * emitted below, but we need to use ins->dreg
13107                                                                          * since it refers to the store emitted earlier.
13108                                                                          */
13109                                                                         sreg = ins->dreg;
13110                                                                 }
13111                                                                 g_assert (sreg != -1);
13112                                                                 vreg_to_lvreg [var->dreg] = sreg;
13113                                                                 g_assert (lvregs_len < 1024);
13114                                                                 lvregs [lvregs_len ++] = var->dreg;
13115                                                         }
13116                                                 }
13117
13118                                                 sregs [srcindex] = sreg;
13119                                                 //mono_inst_set_src_registers (ins, sregs);
13120
13121 #if SIZEOF_REGISTER != 8
13122                                                 if (regtype == 'l') {
13123                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
13124                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13125                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
13126                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13127                                                         use_ins = load_ins;
13128                                                 }
13129                                                 else
13130 #endif
13131                                                 {
13132 #if SIZEOF_REGISTER == 4
13133                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
13134 #endif
13135                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
13136                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
13137                                                         use_ins = load_ins;
13138                                                 }
13139                                         }
13140
13141                                         if (var->dreg < orig_next_vreg) {
13142                                                 live_range_end [var->dreg] = use_ins;
13143                                                 live_range_end_bb [var->dreg] = bb;
13144                                         }
13145
13146                                         if (cfg->compute_gc_maps && var->dreg < orig_next_vreg && (var->flags & MONO_INST_GC_TRACK)) {
13147                                                 MonoInst *tmp;
13148
13149                                                 MONO_INST_NEW (cfg, tmp, OP_GC_LIVENESS_USE);
13150                                                 tmp->inst_c1 = var->dreg;
13151                                                 mono_bblock_insert_after_ins (bb, ins, tmp);
13152                                         }
13153                                 }
13154                         }
13155                         mono_inst_set_src_registers (ins, sregs);
13156
13157                         if (dest_has_lvreg) {
13158                                 g_assert (ins->dreg != -1);
13159                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
13160                                 g_assert (lvregs_len < 1024);
13161                                 lvregs [lvregs_len ++] = prev_dreg;
13162                                 dest_has_lvreg = FALSE;
13163                         }
13164
13165                         if (store) {
13166                                 tmp_reg = ins->dreg;
13167                                 ins->dreg = ins->sreg2;
13168                                 ins->sreg2 = tmp_reg;
13169                         }
13170
13171                         if (MONO_IS_CALL (ins)) {
13172                                 /* Clear vreg_to_lvreg array */
13173                                 for (i = 0; i < lvregs_len; i++)
13174                                         vreg_to_lvreg [lvregs [i]] = 0;
13175                                 lvregs_len = 0;
13176                         } else if (ins->opcode == OP_NOP) {
13177                                 ins->dreg = -1;
13178                                 MONO_INST_NULLIFY_SREGS (ins);
13179                         }
13180
13181                         if (cfg->verbose_level > 2)
13182                                 mono_print_ins_index (1, ins);
13183                 }
13184
13185                 /* Extend the live range based on the liveness info */
13186                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
13187                         for (i = 0; i < cfg->num_varinfo; i ++) {
13188                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
13189
13190                                 if (vreg_is_volatile (cfg, vi->vreg))
13191                                         /* The liveness info is incomplete */
13192                                         continue;
13193
13194                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
13195                                         /* Live from at least the first ins of this bb */
13196                                         live_range_start [vi->vreg] = bb->code;
13197                                         live_range_start_bb [vi->vreg] = bb;
13198                                 }
13199
13200                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
13201                                         /* Live at least until the last ins of this bb */
13202                                         live_range_end [vi->vreg] = bb->last_ins;
13203                                         live_range_end_bb [vi->vreg] = bb;
13204                                 }
13205                         }
13206                 }
13207         }
13208         
13209 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
13210         /*
13211          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
13212          * by storing the current native offset into MonoMethodVar->live_range_start/end.
13213          */
13214         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
13215                 for (i = 0; i < cfg->num_varinfo; ++i) {
13216                         int vreg = MONO_VARINFO (cfg, i)->vreg;
13217                         MonoInst *ins;
13218
13219                         if (live_range_start [vreg]) {
13220                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
13221                                 ins->inst_c0 = i;
13222                                 ins->inst_c1 = vreg;
13223                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
13224                         }
13225                         if (live_range_end [vreg]) {
13226                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
13227                                 ins->inst_c0 = i;
13228                                 ins->inst_c1 = vreg;
13229                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
13230                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
13231                                 else
13232                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
13233                         }
13234                 }
13235         }
13236 #endif
13237
13238         if (cfg->gsharedvt_locals_var_ins) {
13239                 /* Nullify if unused */
13240                 cfg->gsharedvt_locals_var_ins->opcode = OP_PCONST;
13241                 cfg->gsharedvt_locals_var_ins->inst_imm = 0;
13242         }
13243
13244         g_free (live_range_start);
13245         g_free (live_range_end);
13246         g_free (live_range_start_bb);
13247         g_free (live_range_end_bb);
13248 }
13249
13250 /**
13251  * FIXME:
13252  * - use 'iadd' instead of 'int_add'
13253  * - handling ovf opcodes: decompose in method_to_ir.
13254  * - unify iregs/fregs
13255  *   -> partly done, the missing parts are:
13256  *   - a more complete unification would involve unifying the hregs as well, so
13257  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
13258  *     would no longer map to the machine hregs, so the code generators would need to
13259  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
13260  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
13261  *     fp/non-fp branches speeds it up by about 15%.
13262  * - use sext/zext opcodes instead of shifts
13263  * - add OP_ICALL
13264  * - get rid of TEMPLOADs if possible and use vregs instead
13265  * - clean up usage of OP_P/OP_ opcodes
13266  * - cleanup usage of DUMMY_USE
13267  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
13268  *   stack
13269  * - set the stack type and allocate a dreg in the EMIT_NEW macros
13270  * - get rid of all the <foo>2 stuff when the new JIT is ready.
13271  * - make sure handle_stack_args () is called before the branch is emitted
13272  * - when the new IR is done, get rid of all unused stuff
13273  * - COMPARE/BEQ as separate instructions or unify them ?
13274  *   - keeping them separate allows specialized compare instructions like
13275  *     compare_imm, compare_membase
13276  *   - most back ends unify fp compare+branch, fp compare+ceq
13277  * - integrate mono_save_args into inline_method
13278  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
13279  * - handle long shift opts on 32 bit platforms somehow: they require 
13280  *   3 sregs (2 for arg1 and 1 for arg2)
13281  * - make byref a 'normal' type.
13282  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
13283  *   variable if needed.
13284  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
13285  *   like inline_method.
13286  * - remove inlining restrictions
13287  * - fix LNEG and enable cfold of INEG
13288  * - generalize x86 optimizations like ldelema as a peephole optimization
13289  * - add store_mem_imm for amd64
13290  * - optimize the loading of the interruption flag in the managed->native wrappers
13291  * - avoid special handling of OP_NOP in passes
13292  * - move code inserting instructions into one function/macro.
13293  * - try a coalescing phase after liveness analysis
13294  * - add float -> vreg conversion + local optimizations on !x86
13295  * - figure out how to handle decomposed branches during optimizations, ie.
13296  *   compare+branch, op_jump_table+op_br etc.
13297  * - promote RuntimeXHandles to vregs
13298  * - vtype cleanups:
13299  *   - add a NEW_VARLOADA_VREG macro
13300  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
13301  *   accessing vtype fields.
13302  * - get rid of I8CONST on 64 bit platforms
13303  * - dealing with the increase in code size due to branches created during opcode
13304  *   decomposition:
13305  *   - use extended basic blocks
13306  *     - all parts of the JIT
13307  *     - handle_global_vregs () && local regalloc
13308  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
13309  * - sources of increase in code size:
13310  *   - vtypes
13311  *   - long compares
13312  *   - isinst and castclass
13313  *   - lvregs not allocated to global registers even if used multiple times
13314  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
13315  *   meaningful.
13316  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
13317  * - add all micro optimizations from the old JIT
13318  * - put tree optimizations into the deadce pass
13319  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
13320  *   specific function.
13321  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
13322  *   fcompare + branchCC.
13323  * - create a helper function for allocating a stack slot, taking into account 
13324  *   MONO_CFG_HAS_SPILLUP.
13325  * - merge r68207.
13326  * - merge the ia64 switch changes.
13327  * - optimize mono_regstate2_alloc_int/float.
13328  * - fix the pessimistic handling of variables accessed in exception handler blocks.
13329  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
13330  *   parts of the tree could be separated by other instructions, killing the tree
13331  *   arguments, or stores killing loads etc. Also, should we fold loads into other
13332  *   instructions if the result of the load is used multiple times ?
13333  * - make the REM_IMM optimization in mini-x86.c arch-independent.
13334  * - LAST MERGE: 108395.
13335  * - when returning vtypes in registers, generate IR and append it to the end of the
13336  *   last bb instead of doing it in the epilog.
13337  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
13338  */
13339
13340 /*
13341
13342 NOTES
13343 -----
13344
13345 - When to decompose opcodes:
13346   - earlier: this makes some optimizations hard to implement, since the low level IR
13347   no longer contains the neccessary information. But it is easier to do.
13348   - later: harder to implement, enables more optimizations.
13349 - Branches inside bblocks:
13350   - created when decomposing complex opcodes. 
13351     - branches to another bblock: harmless, but not tracked by the branch 
13352       optimizations, so need to branch to a label at the start of the bblock.
13353     - branches to inside the same bblock: very problematic, trips up the local
13354       reg allocator. Can be fixed by spitting the current bblock, but that is a
13355       complex operation, since some local vregs can become global vregs etc.
13356 - Local/global vregs:
13357   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
13358     local register allocator.
13359   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
13360     structure, created by mono_create_var (). Assigned to hregs or the stack by
13361     the global register allocator.
13362 - When to do optimizations like alu->alu_imm:
13363   - earlier -> saves work later on since the IR will be smaller/simpler
13364   - later -> can work on more instructions
13365 - Handling of valuetypes:
13366   - When a vtype is pushed on the stack, a new temporary is created, an 
13367     instruction computing its address (LDADDR) is emitted and pushed on
13368     the stack. Need to optimize cases when the vtype is used immediately as in
13369     argument passing, stloc etc.
13370 - Instead of the to_end stuff in the old JIT, simply call the function handling
13371   the values on the stack before emitting the last instruction of the bb.
13372 */
13373
13374 #endif /* DISABLE_JIT */