Remove one more compile-time dependency on sgen.
[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  */
10
11 #include <config.h>
12 #include <signal.h>
13
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17
18 #include <math.h>
19 #include <string.h>
20 #include <ctype.h>
21
22 #ifdef HAVE_SYS_TIME_H
23 #include <sys/time.h>
24 #endif
25
26 #ifdef HAVE_ALLOCA_H
27 #include <alloca.h>
28 #endif
29
30 #include <mono/utils/memcheck.h>
31
32 #include <mono/metadata/assembly.h>
33 #include <mono/metadata/attrdefs.h>
34 #include <mono/metadata/loader.h>
35 #include <mono/metadata/tabledefs.h>
36 #include <mono/metadata/class.h>
37 #include <mono/metadata/object.h>
38 #include <mono/metadata/exception.h>
39 #include <mono/metadata/opcodes.h>
40 #include <mono/metadata/mono-endian.h>
41 #include <mono/metadata/tokentype.h>
42 #include <mono/metadata/tabledefs.h>
43 #include <mono/metadata/marshal.h>
44 #include <mono/metadata/debug-helpers.h>
45 #include <mono/metadata/mono-debug.h>
46 #include <mono/metadata/gc-internal.h>
47 #include <mono/metadata/security-manager.h>
48 #include <mono/metadata/threads-types.h>
49 #include <mono/metadata/security-core-clr.h>
50 #include <mono/metadata/monitor.h>
51 #include <mono/metadata/profiler-private.h>
52 #include <mono/metadata/profiler.h>
53 #include <mono/utils/mono-compiler.h>
54 #include <mono/metadata/mono-basic-block.h>
55
56 #include "mini.h"
57 #include "trace.h"
58
59 #include "ir-emit.h"
60
61 #include "jit-icalls.h"
62 #include "jit.h"
63 #include "debugger-agent.h"
64
65 #define BRANCH_COST 10
66 #define INLINE_LENGTH_LIMIT 20
67 #define INLINE_FAILURE do {\
68                 if ((cfg->method != method) && (method->wrapper_type == MONO_WRAPPER_NONE))\
69                         goto inline_failure;\
70         } while (0)
71 #define CHECK_CFG_EXCEPTION do {\
72                 if (cfg->exception_type != MONO_EXCEPTION_NONE)\
73                         goto exception_exit;\
74         } while (0)
75 #define METHOD_ACCESS_FAILURE do {      \
76                 char *method_fname = mono_method_full_name (method, TRUE);      \
77                 char *cil_method_fname = mono_method_full_name (cil_method, TRUE);      \
78                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_METHOD_ACCESS);             \
79                 cfg->exception_message = g_strdup_printf ("Method `%s' is inaccessible from method `%s'\n", cil_method_fname, method_fname);    \
80                 g_free (method_fname);  \
81                 g_free (cil_method_fname);      \
82                 goto exception_exit;    \
83         } while (0)
84 #define FIELD_ACCESS_FAILURE do {       \
85                 char *method_fname = mono_method_full_name (method, TRUE);      \
86                 char *field_fname = mono_field_full_name (field);       \
87                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_FIELD_ACCESS);              \
88                 cfg->exception_message = g_strdup_printf ("Field `%s' is inaccessible from method `%s'\n", field_fname, method_fname);  \
89                 g_free (method_fname);  \
90                 g_free (field_fname);   \
91                 goto exception_exit;    \
92         } while (0)
93 #define GENERIC_SHARING_FAILURE(opcode) do {            \
94                 if (cfg->generic_sharing_context) {     \
95             if (cfg->verbose_level > 2) \
96                             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__); \
97                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_GENERIC_SHARING_FAILED); \
98                         goto exception_exit;    \
99                 }                       \
100         } while (0)
101 #define OUT_OF_MEMORY_FAILURE do {      \
102                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_OUT_OF_MEMORY);             \
103                 goto exception_exit;    \
104         } while (0)
105 /* Determine whenever 'ins' represents a load of the 'this' argument */
106 #define MONO_CHECK_THIS(ins) (mono_method_signature (cfg->method)->hasthis && ((ins)->opcode == OP_MOVE) && ((ins)->sreg1 == cfg->args [0]->dreg))
107
108 static int ldind_to_load_membase (int opcode);
109 static int stind_to_store_membase (int opcode);
110
111 int mono_op_to_op_imm (int opcode);
112 int mono_op_to_op_imm_noemul (int opcode);
113
114 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
115 void mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native);
116 void mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass);
117
118 /* helper methods signatures */
119 static MonoMethodSignature *helper_sig_class_init_trampoline = NULL;
120 static MonoMethodSignature *helper_sig_domain_get = NULL;
121 static MonoMethodSignature *helper_sig_generic_class_init_trampoline = NULL;
122 static MonoMethodSignature *helper_sig_generic_class_init_trampoline_llvm = NULL;
123 static MonoMethodSignature *helper_sig_rgctx_lazy_fetch_trampoline = NULL;
124 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline = NULL;
125 static MonoMethodSignature *helper_sig_monitor_enter_exit_trampoline_llvm = NULL;
126
127 /*
128  * Instruction metadata
129  */
130 #ifdef MINI_OP
131 #undef MINI_OP
132 #endif
133 #ifdef MINI_OP3
134 #undef MINI_OP3
135 #endif
136 #define MINI_OP(a,b,dest,src1,src2) dest, src1, src2, ' ',
137 #define MINI_OP3(a,b,dest,src1,src2,src3) dest, src1, src2, src3,
138 #define NONE ' '
139 #define IREG 'i'
140 #define FREG 'f'
141 #define VREG 'v'
142 #define XREG 'x'
143 #if SIZEOF_REGISTER == 8
144 #define LREG IREG
145 #else
146 #define LREG 'l'
147 #endif
148 /* keep in sync with the enum in mini.h */
149 const char
150 ins_info[] = {
151 #include "mini-ops.h"
152 };
153 #undef MINI_OP
154 #undef MINI_OP3
155
156 #define MINI_OP(a,b,dest,src1,src2) ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0)),
157 #define MINI_OP3(a,b,dest,src1,src2,src3) ((src3) != NONE ? 3 : ((src2) != NONE ? 2 : ((src1) != NONE ? 1 : 0))),
158 /* 
159  * This should contain the index of the last sreg + 1. This is not the same
160  * as the number of sregs for opcodes like IA64_CMP_EQ_IMM.
161  */
162 const gint8 ins_sreg_counts[] = {
163 #include "mini-ops.h"
164 };
165 #undef MINI_OP
166 #undef MINI_OP3
167
168 #define MONO_INIT_VARINFO(vi,id) do { \
169         (vi)->range.first_use.pos.bid = 0xffff; \
170         (vi)->reg = -1; \
171         (vi)->idx = (id); \
172 } while (0)
173
174 void
175 mono_inst_set_src_registers (MonoInst *ins, int *regs)
176 {
177         ins->sreg1 = regs [0];
178         ins->sreg2 = regs [1];
179         ins->sreg3 = regs [2];
180 }
181
182 guint32
183 mono_alloc_ireg (MonoCompile *cfg)
184 {
185         return alloc_ireg (cfg);
186 }
187
188 guint32
189 mono_alloc_freg (MonoCompile *cfg)
190 {
191         return alloc_freg (cfg);
192 }
193
194 guint32
195 mono_alloc_preg (MonoCompile *cfg)
196 {
197         return alloc_preg (cfg);
198 }
199
200 guint32
201 mono_alloc_dreg (MonoCompile *cfg, MonoStackType stack_type)
202 {
203         return alloc_dreg (cfg, stack_type);
204 }
205
206 guint
207 mono_type_to_regmove (MonoCompile *cfg, MonoType *type)
208 {
209         if (type->byref)
210                 return OP_MOVE;
211
212 handle_enum:
213         switch (type->type) {
214         case MONO_TYPE_I1:
215         case MONO_TYPE_U1:
216         case MONO_TYPE_BOOLEAN:
217                 return OP_MOVE;
218         case MONO_TYPE_I2:
219         case MONO_TYPE_U2:
220         case MONO_TYPE_CHAR:
221                 return OP_MOVE;
222         case MONO_TYPE_I4:
223         case MONO_TYPE_U4:
224                 return OP_MOVE;
225         case MONO_TYPE_I:
226         case MONO_TYPE_U:
227         case MONO_TYPE_PTR:
228         case MONO_TYPE_FNPTR:
229                 return OP_MOVE;
230         case MONO_TYPE_CLASS:
231         case MONO_TYPE_STRING:
232         case MONO_TYPE_OBJECT:
233         case MONO_TYPE_SZARRAY:
234         case MONO_TYPE_ARRAY:    
235                 return OP_MOVE;
236         case MONO_TYPE_I8:
237         case MONO_TYPE_U8:
238 #if SIZEOF_REGISTER == 8
239                 return OP_MOVE;
240 #else
241                 return OP_LMOVE;
242 #endif
243         case MONO_TYPE_R4:
244                 return OP_FMOVE;
245         case MONO_TYPE_R8:
246                 return OP_FMOVE;
247         case MONO_TYPE_VALUETYPE:
248                 if (type->data.klass->enumtype) {
249                         type = mono_class_enum_basetype (type->data.klass);
250                         goto handle_enum;
251                 }
252                 if (MONO_CLASS_IS_SIMD (cfg, mono_class_from_mono_type (type)))
253                         return OP_XMOVE;
254                 return OP_VMOVE;
255         case MONO_TYPE_TYPEDBYREF:
256                 return OP_VMOVE;
257         case MONO_TYPE_GENERICINST:
258                 type = &type->data.generic_class->container_class->byval_arg;
259                 goto handle_enum;
260         case MONO_TYPE_VAR:
261         case MONO_TYPE_MVAR:
262                 g_assert (cfg->generic_sharing_context);
263                 return OP_MOVE;
264         default:
265                 g_error ("unknown type 0x%02x in type_to_regstore", type->type);
266         }
267         return -1;
268 }
269
270 void
271 mono_print_bb (MonoBasicBlock *bb, const char *msg)
272 {
273         int i;
274         MonoInst *tree;
275
276         printf ("\n%s %d: [IN: ", msg, bb->block_num);
277         for (i = 0; i < bb->in_count; ++i)
278                 printf (" BB%d(%d)", bb->in_bb [i]->block_num, bb->in_bb [i]->dfn);
279         printf (", OUT: ");
280         for (i = 0; i < bb->out_count; ++i)
281                 printf (" BB%d(%d)", bb->out_bb [i]->block_num, bb->out_bb [i]->dfn);
282         printf (" ]\n");
283         for (tree = bb->code; tree; tree = tree->next)
284                 mono_print_ins_index (-1, tree);
285 }
286
287 /* 
288  * Can't put this at the beginning, since other files reference stuff from this
289  * file.
290  */
291 #ifndef DISABLE_JIT
292
293 #define UNVERIFIED do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto unverified; } while (0)
294
295 #define LOAD_ERROR do { if (mini_get_debug_options ()->break_on_unverified) G_BREAKPOINT (); else goto load_error; } while (0)
296
297 #define GET_BBLOCK(cfg,tblock,ip) do {  \
298                 (tblock) = cfg->cil_offset_to_bb [(ip) - cfg->cil_start]; \
299                 if (!(tblock)) {        \
300                         if ((ip) >= end || (ip) < header->code) UNVERIFIED; \
301             NEW_BBLOCK (cfg, (tblock)); \
302                         (tblock)->cil_code = (ip);      \
303                         ADD_BBLOCK (cfg, (tblock));     \
304                 } \
305         } while (0)
306
307 #if defined(TARGET_X86) || defined(TARGET_AMD64)
308 #define EMIT_NEW_X86_LEA(cfg,dest,sr1,sr2,shift,imm) do { \
309                 MONO_INST_NEW (cfg, dest, OP_X86_LEA); \
310                 (dest)->dreg = alloc_preg ((cfg)); \
311                 (dest)->sreg1 = (sr1); \
312                 (dest)->sreg2 = (sr2); \
313                 (dest)->inst_imm = (imm); \
314                 (dest)->backend.shift_amount = (shift); \
315                 MONO_ADD_INS ((cfg)->cbb, (dest)); \
316         } while (0)
317 #endif
318
319 #if SIZEOF_REGISTER == 8
320 #define ADD_WIDEN_OP(ins, arg1, arg2) do { \
321                 /* FIXME: Need to add many more cases */ \
322                 if ((arg1)->type == STACK_PTR && (arg2)->type == STACK_I4) {    \
323                         MonoInst *widen; \
324                         int dr = alloc_preg (cfg); \
325                         EMIT_NEW_UNALU (cfg, widen, OP_SEXT_I4, dr, (arg2)->dreg); \
326                         (ins)->sreg2 = widen->dreg; \
327                 } \
328         } while (0)
329 #else
330 #define ADD_WIDEN_OP(ins, arg1, arg2)
331 #endif
332
333 #define ADD_BINOP(op) do {      \
334                 MONO_INST_NEW (cfg, ins, (op)); \
335                 sp -= 2;        \
336                 ins->sreg1 = sp [0]->dreg;      \
337                 ins->sreg2 = sp [1]->dreg;      \
338                 type_from_op (ins, sp [0], sp [1]);     \
339                 CHECK_TYPE (ins);       \
340                 /* Have to insert a widening op */               \
341         ADD_WIDEN_OP (ins, sp [0], sp [1]); \
342         ins->dreg = alloc_dreg ((cfg), (ins)->type); \
343         MONO_ADD_INS ((cfg)->cbb, (ins)); \
344         *sp++ = mono_decompose_opcode ((cfg), (ins)); \
345         } while (0)
346
347 #define ADD_UNOP(op) do {       \
348                 MONO_INST_NEW (cfg, ins, (op)); \
349                 sp--;   \
350                 ins->sreg1 = sp [0]->dreg;      \
351                 type_from_op (ins, sp [0], NULL);       \
352                 CHECK_TYPE (ins);       \
353         (ins)->dreg = alloc_dreg ((cfg), (ins)->type); \
354         MONO_ADD_INS ((cfg)->cbb, (ins)); \
355                 *sp++ = mono_decompose_opcode (cfg, ins); \
356         } while (0)
357
358 #define ADD_BINCOND(next_block) do {    \
359                 MonoInst *cmp;  \
360                 sp -= 2; \
361                 MONO_INST_NEW(cfg, cmp, OP_COMPARE);    \
362                 cmp->sreg1 = sp [0]->dreg;      \
363                 cmp->sreg2 = sp [1]->dreg;      \
364                 type_from_op (cmp, sp [0], sp [1]);     \
365                 CHECK_TYPE (cmp);       \
366                 type_from_op (ins, sp [0], sp [1]);     \
367                 ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);      \
368                 GET_BBLOCK (cfg, tblock, target);               \
369                 link_bblock (cfg, bblock, tblock);      \
370                 ins->inst_true_bb = tblock;     \
371                 if ((next_block)) {     \
372                         link_bblock (cfg, bblock, (next_block));        \
373                         ins->inst_false_bb = (next_block);      \
374                         start_new_bblock = 1;   \
375                 } else {        \
376                         GET_BBLOCK (cfg, tblock, ip);           \
377                         link_bblock (cfg, bblock, tblock);      \
378                         ins->inst_false_bb = tblock;    \
379                         start_new_bblock = 2;   \
380                 }       \
381                 if (sp != stack_start) {                                                                        \
382                     handle_stack_args (cfg, stack_start, sp - stack_start); \
383                         CHECK_UNVERIFIABLE (cfg); \
384                 } \
385         MONO_ADD_INS (bblock, cmp); \
386                 MONO_ADD_INS (bblock, ins);     \
387         } while (0)
388
389 /* *
390  * link_bblock: Links two basic blocks
391  *
392  * links two basic blocks in the control flow graph, the 'from'
393  * argument is the starting block and the 'to' argument is the block
394  * the control flow ends to after 'from'.
395  */
396 static void
397 link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
398 {
399         MonoBasicBlock **newa;
400         int i, found;
401
402 #if 0
403         if (from->cil_code) {
404                 if (to->cil_code)
405                         printf ("edge from IL%04x to IL_%04x\n", from->cil_code - cfg->cil_code, to->cil_code - cfg->cil_code);
406                 else
407                         printf ("edge from IL%04x to exit\n", from->cil_code - cfg->cil_code);
408         } else {
409                 if (to->cil_code)
410                         printf ("edge from entry to IL_%04x\n", to->cil_code - cfg->cil_code);
411                 else
412                         printf ("edge from entry to exit\n");
413         }
414 #endif
415
416         found = FALSE;
417         for (i = 0; i < from->out_count; ++i) {
418                 if (to == from->out_bb [i]) {
419                         found = TRUE;
420                         break;
421                 }
422         }
423         if (!found) {
424                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (from->out_count + 1));
425                 for (i = 0; i < from->out_count; ++i) {
426                         newa [i] = from->out_bb [i];
427                 }
428                 newa [i] = to;
429                 from->out_count++;
430                 from->out_bb = newa;
431         }
432
433         found = FALSE;
434         for (i = 0; i < to->in_count; ++i) {
435                 if (from == to->in_bb [i]) {
436                         found = TRUE;
437                         break;
438                 }
439         }
440         if (!found) {
441                 newa = mono_mempool_alloc (cfg->mempool, sizeof (gpointer) * (to->in_count + 1));
442                 for (i = 0; i < to->in_count; ++i) {
443                         newa [i] = to->in_bb [i];
444                 }
445                 newa [i] = from;
446                 to->in_count++;
447                 to->in_bb = newa;
448         }
449 }
450
451 void
452 mono_link_bblock (MonoCompile *cfg, MonoBasicBlock *from, MonoBasicBlock* to)
453 {
454         link_bblock (cfg, from, to);
455 }
456
457 /**
458  * mono_find_block_region:
459  *
460  *   We mark each basic block with a region ID. We use that to avoid BB
461  *   optimizations when blocks are in different regions.
462  *
463  * Returns:
464  *   A region token that encodes where this region is, and information
465  *   about the clause owner for this block.
466  *
467  *   The region encodes the try/catch/filter clause that owns this block
468  *   as well as the type.  -1 is a special value that represents a block
469  *   that is in none of try/catch/filter.
470  */
471 static int
472 mono_find_block_region (MonoCompile *cfg, int offset)
473 {
474         MonoMethodHeader *header = cfg->header;
475         MonoExceptionClause *clause;
476         int i;
477
478         for (i = 0; i < header->num_clauses; ++i) {
479                 clause = &header->clauses [i];
480                 if ((clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) && (offset >= clause->data.filter_offset) &&
481                     (offset < (clause->handler_offset)))
482                         return ((i + 1) << 8) | MONO_REGION_FILTER | clause->flags;
483                            
484                 if (MONO_OFFSET_IN_HANDLER (clause, offset)) {
485                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY)
486                                 return ((i + 1) << 8) | MONO_REGION_FINALLY | clause->flags;
487                         else if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
488                                 return ((i + 1) << 8) | MONO_REGION_FAULT | clause->flags;
489                         else
490                                 return ((i + 1) << 8) | MONO_REGION_CATCH | clause->flags;
491                 }
492
493                 if (MONO_OFFSET_IN_CLAUSE (clause, offset))
494                         return ((i + 1) << 8) | clause->flags;
495         }
496
497         return -1;
498 }
499
500 static GList*
501 mono_find_final_block (MonoCompile *cfg, unsigned char *ip, unsigned char *target, int type)
502 {
503         MonoMethodHeader *header = cfg->header;
504         MonoExceptionClause *clause;
505         int i;
506         GList *res = NULL;
507
508         for (i = 0; i < header->num_clauses; ++i) {
509                 clause = &header->clauses [i];
510                 if (MONO_OFFSET_IN_CLAUSE (clause, (ip - header->code)) && 
511                     (!MONO_OFFSET_IN_CLAUSE (clause, (target - header->code)))) {
512                         if (clause->flags == type)
513                                 res = g_list_append (res, clause);
514                 }
515         }
516         return res;
517 }
518
519 static void
520 mono_create_spvar_for_region (MonoCompile *cfg, int region)
521 {
522         MonoInst *var;
523
524         var = g_hash_table_lookup (cfg->spvars, GINT_TO_POINTER (region));
525         if (var)
526                 return;
527
528         var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
529         /* prevent it from being register allocated */
530         var->flags |= MONO_INST_INDIRECT;
531
532         g_hash_table_insert (cfg->spvars, GINT_TO_POINTER (region), var);
533 }
534
535 MonoInst *
536 mono_find_exvar_for_offset (MonoCompile *cfg, int offset)
537 {
538         return g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
539 }
540
541 static MonoInst*
542 mono_create_exvar_for_offset (MonoCompile *cfg, int offset)
543 {
544         MonoInst *var;
545
546         var = g_hash_table_lookup (cfg->exvars, GINT_TO_POINTER (offset));
547         if (var)
548                 return var;
549
550         var = mono_compile_create_var (cfg, &mono_defaults.object_class->byval_arg, OP_LOCAL);
551         /* prevent it from being register allocated */
552         var->flags |= MONO_INST_INDIRECT;
553
554         g_hash_table_insert (cfg->exvars, GINT_TO_POINTER (offset), var);
555
556         return var;
557 }
558
559 /*
560  * Returns the type used in the eval stack when @type is loaded.
561  * FIXME: return a MonoType/MonoClass for the byref and VALUETYPE cases.
562  */
563 void
564 type_to_eval_stack_type (MonoCompile *cfg, MonoType *type, MonoInst *inst)
565 {
566         MonoClass *klass;
567
568         inst->klass = klass = mono_class_from_mono_type (type);
569         if (type->byref) {
570                 inst->type = STACK_MP;
571                 return;
572         }
573
574 handle_enum:
575         switch (type->type) {
576         case MONO_TYPE_VOID:
577                 inst->type = STACK_INV;
578                 return;
579         case MONO_TYPE_I1:
580         case MONO_TYPE_U1:
581         case MONO_TYPE_BOOLEAN:
582         case MONO_TYPE_I2:
583         case MONO_TYPE_U2:
584         case MONO_TYPE_CHAR:
585         case MONO_TYPE_I4:
586         case MONO_TYPE_U4:
587                 inst->type = STACK_I4;
588                 return;
589         case MONO_TYPE_I:
590         case MONO_TYPE_U:
591         case MONO_TYPE_PTR:
592         case MONO_TYPE_FNPTR:
593                 inst->type = STACK_PTR;
594                 return;
595         case MONO_TYPE_CLASS:
596         case MONO_TYPE_STRING:
597         case MONO_TYPE_OBJECT:
598         case MONO_TYPE_SZARRAY:
599         case MONO_TYPE_ARRAY:    
600                 inst->type = STACK_OBJ;
601                 return;
602         case MONO_TYPE_I8:
603         case MONO_TYPE_U8:
604                 inst->type = STACK_I8;
605                 return;
606         case MONO_TYPE_R4:
607         case MONO_TYPE_R8:
608                 inst->type = STACK_R8;
609                 return;
610         case MONO_TYPE_VALUETYPE:
611                 if (type->data.klass->enumtype) {
612                         type = mono_class_enum_basetype (type->data.klass);
613                         goto handle_enum;
614                 } else {
615                         inst->klass = klass;
616                         inst->type = STACK_VTYPE;
617                         return;
618                 }
619         case MONO_TYPE_TYPEDBYREF:
620                 inst->klass = mono_defaults.typed_reference_class;
621                 inst->type = STACK_VTYPE;
622                 return;
623         case MONO_TYPE_GENERICINST:
624                 type = &type->data.generic_class->container_class->byval_arg;
625                 goto handle_enum;
626         case MONO_TYPE_VAR :
627         case MONO_TYPE_MVAR :
628                 /* FIXME: all the arguments must be references for now,
629                  * later look inside cfg and see if the arg num is
630                  * really a reference
631                  */
632                 g_assert (cfg->generic_sharing_context);
633                 inst->type = STACK_OBJ;
634                 return;
635         default:
636                 g_error ("unknown type 0x%02x in eval stack type", type->type);
637         }
638 }
639
640 /*
641  * The following tables are used to quickly validate the IL code in type_from_op ().
642  */
643 static const char
644 bin_num_table [STACK_MAX] [STACK_MAX] = {
645         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
646         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
647         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
648         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_MP,  STACK_INV, STACK_INV},
649         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_R8,  STACK_INV, STACK_INV, STACK_INV},
650         {STACK_INV, STACK_MP,  STACK_INV, STACK_MP,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV},
651         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
652         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
653 };
654
655 static const char 
656 neg_table [] = {
657         STACK_INV, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_INV, STACK_INV, STACK_INV
658 };
659
660 /* reduce the size of this table */
661 static const char
662 bin_int_table [STACK_MAX] [STACK_MAX] = {
663         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
664         {STACK_INV, STACK_I4,  STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
665         {STACK_INV, STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
666         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
667         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
668         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
669         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
670         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
671 };
672
673 static const char
674 bin_comp_table [STACK_MAX] [STACK_MAX] = {
675 /*      Inv i  L  p  F  &  O  vt */
676         {0},
677         {0, 1, 0, 1, 0, 0, 0, 0}, /* i, int32 */
678         {0, 0, 1, 0, 0, 0, 0, 0}, /* L, int64 */
679         {0, 1, 0, 1, 0, 2, 4, 0}, /* p, ptr */
680         {0, 0, 0, 0, 1, 0, 0, 0}, /* F, R8 */
681         {0, 0, 0, 2, 0, 1, 0, 0}, /* &, managed pointer */
682         {0, 0, 0, 4, 0, 0, 3, 0}, /* O, reference */
683         {0, 0, 0, 0, 0, 0, 0, 0}, /* vt value type */
684 };
685
686 /* reduce the size of this table */
687 static const char
688 shift_table [STACK_MAX] [STACK_MAX] = {
689         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
690         {STACK_INV, STACK_I4,  STACK_INV, STACK_I4,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
691         {STACK_INV, STACK_I8,  STACK_INV, STACK_I8,  STACK_INV, STACK_INV, STACK_INV, STACK_INV},
692         {STACK_INV, STACK_PTR, STACK_INV, STACK_PTR, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
693         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
694         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
695         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV},
696         {STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV, STACK_INV}
697 };
698
699 /*
700  * Tables to map from the non-specific opcode to the matching
701  * type-specific opcode.
702  */
703 /* handles from CEE_ADD to CEE_SHR_UN (CEE_REM_UN for floats) */
704 static const guint16
705 binops_op_map [STACK_MAX] = {
706         0, OP_IADD-CEE_ADD, OP_LADD-CEE_ADD, OP_PADD-CEE_ADD, OP_FADD-CEE_ADD, OP_PADD-CEE_ADD
707 };
708
709 /* handles from CEE_NEG to CEE_CONV_U8 */
710 static const guint16
711 unops_op_map [STACK_MAX] = {
712         0, OP_INEG-CEE_NEG, OP_LNEG-CEE_NEG, OP_PNEG-CEE_NEG, OP_FNEG-CEE_NEG, OP_PNEG-CEE_NEG
713 };
714
715 /* handles from CEE_CONV_U2 to CEE_SUB_OVF_UN */
716 static const guint16
717 ovfops_op_map [STACK_MAX] = {
718         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
719 };
720
721 /* handles from CEE_CONV_OVF_I1_UN to CEE_CONV_OVF_U_UN */
722 static const guint16
723 ovf2ops_op_map [STACK_MAX] = {
724         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
725 };
726
727 /* handles from CEE_CONV_OVF_I1 to CEE_CONV_OVF_U8 */
728 static const guint16
729 ovf3ops_op_map [STACK_MAX] = {
730         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
731 };
732
733 /* handles from CEE_BEQ to CEE_BLT_UN */
734 static const guint16
735 beqops_op_map [STACK_MAX] = {
736         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
737 };
738
739 /* handles from CEE_CEQ to CEE_CLT_UN */
740 static const guint16
741 ceqops_op_map [STACK_MAX] = {
742         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
743 };
744
745 /*
746  * Sets ins->type (the type on the eval stack) according to the
747  * type of the opcode and the arguments to it.
748  * Invalid IL code is marked by setting ins->type to the invalid value STACK_INV.
749  *
750  * FIXME: this function sets ins->type unconditionally in some cases, but
751  * it should set it to invalid for some types (a conv.x on an object)
752  */
753 static void
754 type_from_op (MonoInst *ins, MonoInst *src1, MonoInst *src2) {
755
756         switch (ins->opcode) {
757         /* binops */
758         case CEE_ADD:
759         case CEE_SUB:
760         case CEE_MUL:
761         case CEE_DIV:
762         case CEE_REM:
763                 /* FIXME: check unverifiable args for STACK_MP */
764                 ins->type = bin_num_table [src1->type] [src2->type];
765                 ins->opcode += binops_op_map [ins->type];
766                 break;
767         case CEE_DIV_UN:
768         case CEE_REM_UN:
769         case CEE_AND:
770         case CEE_OR:
771         case CEE_XOR:
772                 ins->type = bin_int_table [src1->type] [src2->type];
773                 ins->opcode += binops_op_map [ins->type];
774                 break;
775         case CEE_SHL:
776         case CEE_SHR:
777         case CEE_SHR_UN:
778                 ins->type = shift_table [src1->type] [src2->type];
779                 ins->opcode += binops_op_map [ins->type];
780                 break;
781         case OP_COMPARE:
782         case OP_LCOMPARE:
783         case OP_ICOMPARE:
784                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
785                 if ((src1->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
786                         ins->opcode = OP_LCOMPARE;
787                 else if (src1->type == STACK_R8)
788                         ins->opcode = OP_FCOMPARE;
789                 else
790                         ins->opcode = OP_ICOMPARE;
791                 break;
792         case OP_ICOMPARE_IMM:
793                 ins->type = bin_comp_table [src1->type] [src1->type] ? STACK_I4 : STACK_INV;
794                 if ((src1->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((src1->type == STACK_PTR) || (src1->type == STACK_OBJ) || (src1->type == STACK_MP))))
795                         ins->opcode = OP_LCOMPARE_IMM;          
796                 break;
797         case CEE_BEQ:
798         case CEE_BGE:
799         case CEE_BGT:
800         case CEE_BLE:
801         case CEE_BLT:
802         case CEE_BNE_UN:
803         case CEE_BGE_UN:
804         case CEE_BGT_UN:
805         case CEE_BLE_UN:
806         case CEE_BLT_UN:
807                 ins->opcode += beqops_op_map [src1->type];
808                 break;
809         case OP_CEQ:
810                 ins->type = bin_comp_table [src1->type] [src2->type] ? STACK_I4: STACK_INV;
811                 ins->opcode += ceqops_op_map [src1->type];
812                 break;
813         case OP_CGT:
814         case OP_CGT_UN:
815         case OP_CLT:
816         case OP_CLT_UN:
817                 ins->type = (bin_comp_table [src1->type] [src2->type] & 1) ? STACK_I4: STACK_INV;
818                 ins->opcode += ceqops_op_map [src1->type];
819                 break;
820         /* unops */
821         case CEE_NEG:
822                 ins->type = neg_table [src1->type];
823                 ins->opcode += unops_op_map [ins->type];
824                 break;
825         case CEE_NOT:
826                 if (src1->type >= STACK_I4 && src1->type <= STACK_PTR)
827                         ins->type = src1->type;
828                 else
829                         ins->type = STACK_INV;
830                 ins->opcode += unops_op_map [ins->type];
831                 break;
832         case CEE_CONV_I1:
833         case CEE_CONV_I2:
834         case CEE_CONV_I4:
835         case CEE_CONV_U4:
836                 ins->type = STACK_I4;
837                 ins->opcode += unops_op_map [src1->type];
838                 break;
839         case CEE_CONV_R_UN:
840                 ins->type = STACK_R8;
841                 switch (src1->type) {
842                 case STACK_I4:
843                 case STACK_PTR:
844                         ins->opcode = OP_ICONV_TO_R_UN;
845                         break;
846                 case STACK_I8:
847                         ins->opcode = OP_LCONV_TO_R_UN; 
848                         break;
849                 }
850                 break;
851         case CEE_CONV_OVF_I1:
852         case CEE_CONV_OVF_U1:
853         case CEE_CONV_OVF_I2:
854         case CEE_CONV_OVF_U2:
855         case CEE_CONV_OVF_I4:
856         case CEE_CONV_OVF_U4:
857                 ins->type = STACK_I4;
858                 ins->opcode += ovf3ops_op_map [src1->type];
859                 break;
860         case CEE_CONV_OVF_I_UN:
861         case CEE_CONV_OVF_U_UN:
862                 ins->type = STACK_PTR;
863                 ins->opcode += ovf2ops_op_map [src1->type];
864                 break;
865         case CEE_CONV_OVF_I1_UN:
866         case CEE_CONV_OVF_I2_UN:
867         case CEE_CONV_OVF_I4_UN:
868         case CEE_CONV_OVF_U1_UN:
869         case CEE_CONV_OVF_U2_UN:
870         case CEE_CONV_OVF_U4_UN:
871                 ins->type = STACK_I4;
872                 ins->opcode += ovf2ops_op_map [src1->type];
873                 break;
874         case CEE_CONV_U:
875                 ins->type = STACK_PTR;
876                 switch (src1->type) {
877                 case STACK_I4:
878                         ins->opcode = OP_ICONV_TO_U;
879                         break;
880                 case STACK_PTR:
881                 case STACK_MP:
882 #if SIZEOF_REGISTER == 8
883                         ins->opcode = OP_LCONV_TO_U;
884 #else
885                         ins->opcode = OP_MOVE;
886 #endif
887                         break;
888                 case STACK_I8:
889                         ins->opcode = OP_LCONV_TO_U;
890                         break;
891                 case STACK_R8:
892                         ins->opcode = OP_FCONV_TO_U;
893                         break;
894                 }
895                 break;
896         case CEE_CONV_I8:
897         case CEE_CONV_U8:
898                 ins->type = STACK_I8;
899                 ins->opcode += unops_op_map [src1->type];
900                 break;
901         case CEE_CONV_OVF_I8:
902         case CEE_CONV_OVF_U8:
903                 ins->type = STACK_I8;
904                 ins->opcode += ovf3ops_op_map [src1->type];
905                 break;
906         case CEE_CONV_OVF_U8_UN:
907         case CEE_CONV_OVF_I8_UN:
908                 ins->type = STACK_I8;
909                 ins->opcode += ovf2ops_op_map [src1->type];
910                 break;
911         case CEE_CONV_R4:
912         case CEE_CONV_R8:
913                 ins->type = STACK_R8;
914                 ins->opcode += unops_op_map [src1->type];
915                 break;
916         case OP_CKFINITE:
917                 ins->type = STACK_R8;           
918                 break;
919         case CEE_CONV_U2:
920         case CEE_CONV_U1:
921                 ins->type = STACK_I4;
922                 ins->opcode += ovfops_op_map [src1->type];
923                 break;
924         case CEE_CONV_I:
925         case CEE_CONV_OVF_I:
926         case CEE_CONV_OVF_U:
927                 ins->type = STACK_PTR;
928                 ins->opcode += ovfops_op_map [src1->type];
929                 break;
930         case CEE_ADD_OVF:
931         case CEE_ADD_OVF_UN:
932         case CEE_MUL_OVF:
933         case CEE_MUL_OVF_UN:
934         case CEE_SUB_OVF:
935         case CEE_SUB_OVF_UN:
936                 ins->type = bin_num_table [src1->type] [src2->type];
937                 ins->opcode += ovfops_op_map [src1->type];
938                 if (ins->type == STACK_R8)
939                         ins->type = STACK_INV;
940                 break;
941         case OP_LOAD_MEMBASE:
942                 ins->type = STACK_PTR;
943                 break;
944         case OP_LOADI1_MEMBASE:
945         case OP_LOADU1_MEMBASE:
946         case OP_LOADI2_MEMBASE:
947         case OP_LOADU2_MEMBASE:
948         case OP_LOADI4_MEMBASE:
949         case OP_LOADU4_MEMBASE:
950                 ins->type = STACK_PTR;
951                 break;
952         case OP_LOADI8_MEMBASE:
953                 ins->type = STACK_I8;
954                 break;
955         case OP_LOADR4_MEMBASE:
956         case OP_LOADR8_MEMBASE:
957                 ins->type = STACK_R8;
958                 break;
959         default:
960                 g_error ("opcode 0x%04x not handled in type from op", ins->opcode);
961                 break;
962         }
963
964         if (ins->type == STACK_MP)
965                 ins->klass = mono_defaults.object_class;
966 }
967
968 static const char 
969 ldind_type [] = {
970         STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I4, STACK_I8, STACK_PTR, STACK_R8, STACK_R8, STACK_OBJ
971 };
972
973 #if 0
974
975 static const char
976 param_table [STACK_MAX] [STACK_MAX] = {
977         {0},
978 };
979
980 static int
981 check_values_to_signature (MonoInst *args, MonoType *this, MonoMethodSignature *sig) {
982         int i;
983
984         if (sig->hasthis) {
985                 switch (args->type) {
986                 case STACK_I4:
987                 case STACK_I8:
988                 case STACK_R8:
989                 case STACK_VTYPE:
990                 case STACK_INV:
991                         return 0;
992                 }
993                 args++;
994         }
995         for (i = 0; i < sig->param_count; ++i) {
996                 switch (args [i].type) {
997                 case STACK_INV:
998                         return 0;
999                 case STACK_MP:
1000                         if (!sig->params [i]->byref)
1001                                 return 0;
1002                         continue;
1003                 case STACK_OBJ:
1004                         if (sig->params [i]->byref)
1005                                 return 0;
1006                         switch (sig->params [i]->type) {
1007                         case MONO_TYPE_CLASS:
1008                         case MONO_TYPE_STRING:
1009                         case MONO_TYPE_OBJECT:
1010                         case MONO_TYPE_SZARRAY:
1011                         case MONO_TYPE_ARRAY:
1012                                 break;
1013                         default:
1014                                 return 0;
1015                         }
1016                         continue;
1017                 case STACK_R8:
1018                         if (sig->params [i]->byref)
1019                                 return 0;
1020                         if (sig->params [i]->type != MONO_TYPE_R4 && sig->params [i]->type != MONO_TYPE_R8)
1021                                 return 0;
1022                         continue;
1023                 case STACK_PTR:
1024                 case STACK_I4:
1025                 case STACK_I8:
1026                 case STACK_VTYPE:
1027                         break;
1028                 }
1029                 /*if (!param_table [args [i].type] [sig->params [i]->type])
1030                         return 0;*/
1031         }
1032         return 1;
1033 }
1034 #endif
1035
1036 /*
1037  * When we need a pointer to the current domain many times in a method, we
1038  * call mono_domain_get() once and we store the result in a local variable.
1039  * This function returns the variable that represents the MonoDomain*.
1040  */
1041 inline static MonoInst *
1042 mono_get_domainvar (MonoCompile *cfg)
1043 {
1044         if (!cfg->domainvar)
1045                 cfg->domainvar = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1046         return cfg->domainvar;
1047 }
1048
1049 /*
1050  * The got_var contains the address of the Global Offset Table when AOT 
1051  * compiling.
1052  */
1053 MonoInst *
1054 mono_get_got_var (MonoCompile *cfg)
1055 {
1056 #ifdef MONO_ARCH_NEED_GOT_VAR
1057         if (!cfg->compile_aot)
1058                 return NULL;
1059         if (!cfg->got_var) {
1060                 cfg->got_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1061         }
1062         return cfg->got_var;
1063 #else
1064         return NULL;
1065 #endif
1066 }
1067
1068 static MonoInst *
1069 mono_get_vtable_var (MonoCompile *cfg)
1070 {
1071         g_assert (cfg->generic_sharing_context);
1072
1073         if (!cfg->rgctx_var) {
1074                 cfg->rgctx_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1075                 /* force the var to be stack allocated */
1076                 cfg->rgctx_var->flags |= MONO_INST_INDIRECT;
1077         }
1078
1079         return cfg->rgctx_var;
1080 }
1081
1082 static MonoType*
1083 type_from_stack_type (MonoInst *ins) {
1084         switch (ins->type) {
1085         case STACK_I4: return &mono_defaults.int32_class->byval_arg;
1086         case STACK_I8: return &mono_defaults.int64_class->byval_arg;
1087         case STACK_PTR: return &mono_defaults.int_class->byval_arg;
1088         case STACK_R8: return &mono_defaults.double_class->byval_arg;
1089         case STACK_MP:
1090                 return &ins->klass->this_arg;
1091         case STACK_OBJ: return &mono_defaults.object_class->byval_arg;
1092         case STACK_VTYPE: return &ins->klass->byval_arg;
1093         default:
1094                 g_error ("stack type %d to monotype not handled\n", ins->type);
1095         }
1096         return NULL;
1097 }
1098
1099 static G_GNUC_UNUSED int
1100 type_to_stack_type (MonoType *t)
1101 {
1102         t = mono_type_get_underlying_type (t);
1103         switch (t->type) {
1104         case MONO_TYPE_I1:
1105         case MONO_TYPE_U1:
1106         case MONO_TYPE_BOOLEAN:
1107         case MONO_TYPE_I2:
1108         case MONO_TYPE_U2:
1109         case MONO_TYPE_CHAR:
1110         case MONO_TYPE_I4:
1111         case MONO_TYPE_U4:
1112                 return STACK_I4;
1113         case MONO_TYPE_I:
1114         case MONO_TYPE_U:
1115         case MONO_TYPE_PTR:
1116         case MONO_TYPE_FNPTR:
1117                 return STACK_PTR;
1118         case MONO_TYPE_CLASS:
1119         case MONO_TYPE_STRING:
1120         case MONO_TYPE_OBJECT:
1121         case MONO_TYPE_SZARRAY:
1122         case MONO_TYPE_ARRAY:    
1123                 return STACK_OBJ;
1124         case MONO_TYPE_I8:
1125         case MONO_TYPE_U8:
1126                 return STACK_I8;
1127         case MONO_TYPE_R4:
1128         case MONO_TYPE_R8:
1129                 return STACK_R8;
1130         case MONO_TYPE_VALUETYPE:
1131         case MONO_TYPE_TYPEDBYREF:
1132                 return STACK_VTYPE;
1133         case MONO_TYPE_GENERICINST:
1134                 if (mono_type_generic_inst_is_valuetype (t))
1135                         return STACK_VTYPE;
1136                 else
1137                         return STACK_OBJ;
1138                 break;
1139         default:
1140                 g_assert_not_reached ();
1141         }
1142
1143         return -1;
1144 }
1145
1146 static MonoClass*
1147 array_access_to_klass (int opcode)
1148 {
1149         switch (opcode) {
1150         case CEE_LDELEM_U1:
1151                 return mono_defaults.byte_class;
1152         case CEE_LDELEM_U2:
1153                 return mono_defaults.uint16_class;
1154         case CEE_LDELEM_I:
1155         case CEE_STELEM_I:
1156                 return mono_defaults.int_class;
1157         case CEE_LDELEM_I1:
1158         case CEE_STELEM_I1:
1159                 return mono_defaults.sbyte_class;
1160         case CEE_LDELEM_I2:
1161         case CEE_STELEM_I2:
1162                 return mono_defaults.int16_class;
1163         case CEE_LDELEM_I4:
1164         case CEE_STELEM_I4:
1165                 return mono_defaults.int32_class;
1166         case CEE_LDELEM_U4:
1167                 return mono_defaults.uint32_class;
1168         case CEE_LDELEM_I8:
1169         case CEE_STELEM_I8:
1170                 return mono_defaults.int64_class;
1171         case CEE_LDELEM_R4:
1172         case CEE_STELEM_R4:
1173                 return mono_defaults.single_class;
1174         case CEE_LDELEM_R8:
1175         case CEE_STELEM_R8:
1176                 return mono_defaults.double_class;
1177         case CEE_LDELEM_REF:
1178         case CEE_STELEM_REF:
1179                 return mono_defaults.object_class;
1180         default:
1181                 g_assert_not_reached ();
1182         }
1183         return NULL;
1184 }
1185
1186 /*
1187  * We try to share variables when possible
1188  */
1189 static MonoInst *
1190 mono_compile_get_interface_var (MonoCompile *cfg, int slot, MonoInst *ins)
1191 {
1192         MonoInst *res;
1193         int pos, vnum;
1194
1195         /* inlining can result in deeper stacks */ 
1196         if (slot >= cfg->header->max_stack)
1197                 return mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1198
1199         pos = ins->type - 1 + slot * STACK_MAX;
1200
1201         switch (ins->type) {
1202         case STACK_I4:
1203         case STACK_I8:
1204         case STACK_R8:
1205         case STACK_PTR:
1206         case STACK_MP:
1207         case STACK_OBJ:
1208                 if ((vnum = cfg->intvars [pos]))
1209                         return cfg->varinfo [vnum];
1210                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1211                 cfg->intvars [pos] = res->inst_c0;
1212                 break;
1213         default:
1214                 res = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
1215         }
1216         return res;
1217 }
1218
1219 static void
1220 mono_save_token_info (MonoCompile *cfg, MonoImage *image, guint32 token, gpointer key)
1221 {
1222         /* 
1223          * Don't use this if a generic_context is set, since that means AOT can't
1224          * look up the method using just the image+token.
1225          * table == 0 means this is a reference made from a wrapper.
1226          */
1227         if (cfg->compile_aot && !cfg->generic_context && (mono_metadata_token_table (token) > 0)) {
1228                 MonoJumpInfoToken *jump_info_token = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoJumpInfoToken));
1229                 jump_info_token->image = image;
1230                 jump_info_token->token = token;
1231                 g_hash_table_insert (cfg->token_info_hash, key, jump_info_token);
1232         }
1233 }
1234
1235 /*
1236  * This function is called to handle items that are left on the evaluation stack
1237  * at basic block boundaries. What happens is that we save the values to local variables
1238  * and we reload them later when first entering the target basic block (with the
1239  * handle_loaded_temps () function).
1240  * A single joint point will use the same variables (stored in the array bb->out_stack or
1241  * bb->in_stack, if the basic block is before or after the joint point).
1242  *
1243  * This function needs to be called _before_ emitting the last instruction of
1244  * the bb (i.e. before emitting a branch).
1245  * If the stack merge fails at a join point, cfg->unverifiable is set.
1246  */
1247 static void
1248 handle_stack_args (MonoCompile *cfg, MonoInst **sp, int count)
1249 {
1250         int i, bindex;
1251         MonoBasicBlock *bb = cfg->cbb;
1252         MonoBasicBlock *outb;
1253         MonoInst *inst, **locals;
1254         gboolean found;
1255
1256         if (!count)
1257                 return;
1258         if (cfg->verbose_level > 3)
1259                 printf ("%d item(s) on exit from B%d\n", count, bb->block_num);
1260         if (!bb->out_scount) {
1261                 bb->out_scount = count;
1262                 //printf ("bblock %d has out:", bb->block_num);
1263                 found = FALSE;
1264                 for (i = 0; i < bb->out_count; ++i) {
1265                         outb = bb->out_bb [i];
1266                         /* exception handlers are linked, but they should not be considered for stack args */
1267                         if (outb->flags & BB_EXCEPTION_HANDLER)
1268                                 continue;
1269                         //printf (" %d", outb->block_num);
1270                         if (outb->in_stack) {
1271                                 found = TRUE;
1272                                 bb->out_stack = outb->in_stack;
1273                                 break;
1274                         }
1275                 }
1276                 //printf ("\n");
1277                 if (!found) {
1278                         bb->out_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * count);
1279                         for (i = 0; i < count; ++i) {
1280                                 /* 
1281                                  * try to reuse temps already allocated for this purpouse, if they occupy the same
1282                                  * stack slot and if they are of the same type.
1283                                  * This won't cause conflicts since if 'local' is used to 
1284                                  * store one of the values in the in_stack of a bblock, then
1285                                  * the same variable will be used for the same outgoing stack 
1286                                  * slot as well. 
1287                                  * This doesn't work when inlining methods, since the bblocks
1288                                  * in the inlined methods do not inherit their in_stack from
1289                                  * the bblock they are inlined to. See bug #58863 for an
1290                                  * example.
1291                                  */
1292                                 if (cfg->inlined_method)
1293                                         bb->out_stack [i] = mono_compile_create_var (cfg, type_from_stack_type (sp [i]), OP_LOCAL);
1294                                 else
1295                                         bb->out_stack [i] = mono_compile_get_interface_var (cfg, i, sp [i]);
1296                         }
1297                 }
1298         }
1299
1300         for (i = 0; i < bb->out_count; ++i) {
1301                 outb = bb->out_bb [i];
1302                 /* exception handlers are linked, but they should not be considered for stack args */
1303                 if (outb->flags & BB_EXCEPTION_HANDLER)
1304                         continue;
1305                 if (outb->in_scount) {
1306                         if (outb->in_scount != bb->out_scount) {
1307                                 cfg->unverifiable = TRUE;
1308                                 return;
1309                         }
1310                         continue; /* check they are the same locals */
1311                 }
1312                 outb->in_scount = count;
1313                 outb->in_stack = bb->out_stack;
1314         }
1315
1316         locals = bb->out_stack;
1317         cfg->cbb = bb;
1318         for (i = 0; i < count; ++i) {
1319                 EMIT_NEW_TEMPSTORE (cfg, inst, locals [i]->inst_c0, sp [i]);
1320                 inst->cil_code = sp [i]->cil_code;
1321                 sp [i] = locals [i];
1322                 if (cfg->verbose_level > 3)
1323                         printf ("storing %d to temp %d\n", i, (int)locals [i]->inst_c0);
1324         }
1325
1326         /*
1327          * It is possible that the out bblocks already have in_stack assigned, and
1328          * the in_stacks differ. In this case, we will store to all the different 
1329          * in_stacks.
1330          */
1331
1332         found = TRUE;
1333         bindex = 0;
1334         while (found) {
1335                 /* Find a bblock which has a different in_stack */
1336                 found = FALSE;
1337                 while (bindex < bb->out_count) {
1338                         outb = bb->out_bb [bindex];
1339                         /* exception handlers are linked, but they should not be considered for stack args */
1340                         if (outb->flags & BB_EXCEPTION_HANDLER) {
1341                                 bindex++;
1342                                 continue;
1343                         }
1344                         if (outb->in_stack != locals) {
1345                                 for (i = 0; i < count; ++i) {
1346                                         EMIT_NEW_TEMPSTORE (cfg, inst, outb->in_stack [i]->inst_c0, sp [i]);
1347                                         inst->cil_code = sp [i]->cil_code;
1348                                         sp [i] = locals [i];
1349                                         if (cfg->verbose_level > 3)
1350                                                 printf ("storing %d to temp %d\n", i, (int)outb->in_stack [i]->inst_c0);
1351                                 }
1352                                 locals = outb->in_stack;
1353                                 found = TRUE;
1354                                 break;
1355                         }
1356                         bindex ++;
1357                 }
1358         }
1359 }
1360
1361 /* Emit code which loads interface_offsets [klass->interface_id]
1362  * The array is stored in memory before vtable.
1363 */
1364 static void
1365 mini_emit_load_intf_reg_vtable (MonoCompile *cfg, int intf_reg, int vtable_reg, MonoClass *klass)
1366 {
1367         if (cfg->compile_aot) {
1368                 int ioffset_reg = alloc_preg (cfg);
1369                 int iid_reg = alloc_preg (cfg);
1370
1371                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_ADJUSTED_IID);
1372                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ioffset_reg, iid_reg, vtable_reg);
1373                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, ioffset_reg, 0);
1374         }
1375         else {
1376                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, intf_reg, vtable_reg, -((klass->interface_id + 1) * SIZEOF_VOID_P));
1377         }
1378 }
1379
1380 static void
1381 mini_emit_interface_bitmap_check (MonoCompile *cfg, int intf_bit_reg, int base_reg, int offset, MonoClass *klass)
1382 {
1383         int ibitmap_reg = alloc_preg (cfg);
1384 #ifdef COMPRESSED_INTERFACE_BITMAP
1385         MonoInst *args [2];
1386         MonoInst *res, *ins;
1387         NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, ibitmap_reg, base_reg, offset);
1388         MONO_ADD_INS (cfg->cbb, ins);
1389         args [0] = ins;
1390         if (cfg->compile_aot)
1391                 EMIT_NEW_AOTCONST (cfg, args [1], MONO_PATCH_INFO_IID, klass);
1392         else
1393                 EMIT_NEW_ICONST (cfg, args [1], klass->interface_id);
1394         res = mono_emit_jit_icall (cfg, mono_class_interface_match, args);
1395         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, intf_bit_reg, res->dreg);
1396 #else
1397         int ibitmap_byte_reg = alloc_preg (cfg);
1398
1399         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, ibitmap_reg, base_reg, offset);
1400
1401         if (cfg->compile_aot) {
1402                 int iid_reg = alloc_preg (cfg);
1403                 int shifted_iid_reg = alloc_preg (cfg);
1404                 int ibitmap_byte_address_reg = alloc_preg (cfg);
1405                 int masked_iid_reg = alloc_preg (cfg);
1406                 int iid_one_bit_reg = alloc_preg (cfg);
1407                 int iid_bit_reg = alloc_preg (cfg);
1408                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1409                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_IMM, shifted_iid_reg, iid_reg, 3);
1410                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, ibitmap_byte_address_reg, ibitmap_reg, shifted_iid_reg);
1411                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, ibitmap_byte_reg, ibitmap_byte_address_reg, 0);
1412                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, masked_iid_reg, iid_reg, 7);
1413                 MONO_EMIT_NEW_ICONST (cfg, iid_one_bit_reg, 1);
1414                 MONO_EMIT_NEW_BIALU (cfg, OP_ISHL, iid_bit_reg, iid_one_bit_reg, masked_iid_reg);
1415                 MONO_EMIT_NEW_BIALU (cfg, OP_IAND, intf_bit_reg, ibitmap_byte_reg, iid_bit_reg);
1416         } else {
1417                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, ibitmap_byte_reg, ibitmap_reg, klass->interface_id >> 3);
1418                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_AND_IMM, intf_bit_reg, ibitmap_byte_reg, 1 << (klass->interface_id & 7));
1419         }
1420 #endif
1421 }
1422
1423 /* 
1424  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoClass
1425  * stored in "klass_reg" implements the interface "klass".
1426  */
1427 static void
1428 mini_emit_load_intf_bit_reg_class (MonoCompile *cfg, int intf_bit_reg, int klass_reg, MonoClass *klass)
1429 {
1430         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, interface_bitmap), klass);
1431 }
1432
1433 /* 
1434  * Emit code which loads into "intf_bit_reg" a nonzero value if the MonoVTable
1435  * stored in "vtable_reg" implements the interface "klass".
1436  */
1437 static void
1438 mini_emit_load_intf_bit_reg_vtable (MonoCompile *cfg, int intf_bit_reg, int vtable_reg, MonoClass *klass)
1439 {
1440         mini_emit_interface_bitmap_check (cfg, intf_bit_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, interface_bitmap), klass);
1441 }
1442
1443 /* 
1444  * Emit code which checks whenever the interface id of @klass is smaller than
1445  * than the value given by max_iid_reg.
1446 */
1447 static void
1448 mini_emit_max_iid_check (MonoCompile *cfg, int max_iid_reg, MonoClass *klass,
1449                                                  MonoBasicBlock *false_target)
1450 {
1451         if (cfg->compile_aot) {
1452                 int iid_reg = alloc_preg (cfg);
1453                 MONO_EMIT_NEW_AOTCONST (cfg, iid_reg, klass, MONO_PATCH_INFO_IID);
1454                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, max_iid_reg, iid_reg);
1455         }
1456         else
1457                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, max_iid_reg, klass->interface_id);
1458         if (false_target)
1459                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1460         else
1461                 MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1462 }
1463
1464 /* Same as above, but obtains max_iid from a vtable */
1465 static void
1466 mini_emit_max_iid_check_vtable (MonoCompile *cfg, int vtable_reg, MonoClass *klass,
1467                                                                  MonoBasicBlock *false_target)
1468 {
1469         int max_iid_reg = alloc_preg (cfg);
1470                 
1471         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, max_interface_id));
1472         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1473 }
1474
1475 /* Same as above, but obtains max_iid from a klass */
1476 static void
1477 mini_emit_max_iid_check_class (MonoCompile *cfg, int klass_reg, MonoClass *klass,
1478                                                                  MonoBasicBlock *false_target)
1479 {
1480         int max_iid_reg = alloc_preg (cfg);
1481
1482         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, max_iid_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, max_interface_id));          
1483         mini_emit_max_iid_check (cfg, max_iid_reg, klass, false_target);
1484 }
1485
1486 static void
1487 mini_emit_isninst_cast_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_ins, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1488 {
1489         int idepth_reg = alloc_preg (cfg);
1490         int stypes_reg = alloc_preg (cfg);
1491         int stype = alloc_preg (cfg);
1492
1493         if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1494                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1495                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1496                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBLT_UN, false_target);
1497         }
1498         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1499         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1500         if (klass_ins) {
1501                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, klass_ins->dreg);
1502         } else if (cfg->compile_aot) {
1503                 int const_reg = alloc_preg (cfg);
1504                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1505                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, stype, const_reg);
1506         } else {
1507                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, stype, klass);
1508         }
1509         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, true_target);
1510 }
1511
1512 static void
1513 mini_emit_isninst_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1514 {
1515         mini_emit_isninst_cast_inst (cfg, klass_reg, klass, NULL, false_target, true_target);
1516 }
1517
1518 static void
1519 mini_emit_iface_cast (MonoCompile *cfg, int vtable_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1520 {
1521         int intf_reg = alloc_preg (cfg);
1522
1523         mini_emit_max_iid_check_vtable (cfg, vtable_reg, klass, false_target);
1524         mini_emit_load_intf_bit_reg_vtable (cfg, intf_reg, vtable_reg, klass);
1525         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_reg, 0);
1526         if (true_target)
1527                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1528         else
1529                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");               
1530 }
1531
1532 /*
1533  * Variant of the above that takes a register to the class, not the vtable.
1534  */
1535 static void
1536 mini_emit_iface_class_cast (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoBasicBlock *false_target, MonoBasicBlock *true_target)
1537 {
1538         int intf_bit_reg = alloc_preg (cfg);
1539
1540         mini_emit_max_iid_check_class (cfg, klass_reg, klass, false_target);
1541         mini_emit_load_intf_bit_reg_class (cfg, intf_bit_reg, klass_reg, klass);
1542         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, intf_bit_reg, 0);
1543         if (true_target)
1544                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, true_target);
1545         else
1546                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
1547 }
1548
1549 static inline void
1550 mini_emit_class_check_inst (MonoCompile *cfg, int klass_reg, MonoClass *klass, MonoInst *klass_inst)
1551 {
1552         if (klass_inst) {
1553                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_inst->dreg);
1554         } else if (cfg->compile_aot) {
1555                 int const_reg = alloc_preg (cfg);
1556                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1557                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1558         } else {
1559                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1560         }
1561         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1562 }
1563
1564 static inline void
1565 mini_emit_class_check (MonoCompile *cfg, int klass_reg, MonoClass *klass)
1566 {
1567         return mini_emit_class_check_inst (cfg, klass_reg, klass, NULL);
1568 }
1569
1570 static inline void
1571 mini_emit_class_check_branch (MonoCompile *cfg, int klass_reg, MonoClass *klass, int branch_op, MonoBasicBlock *target)
1572 {
1573         if (cfg->compile_aot) {
1574                 int const_reg = alloc_preg (cfg);
1575                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
1576                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, const_reg);
1577         } else {
1578                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
1579         }
1580         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, branch_op, target);
1581 }
1582
1583 static void
1584 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null);
1585         
1586 static void
1587 mini_emit_castclass_inst (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoInst *klass_inst, MonoBasicBlock *object_is_null)
1588 {
1589         if (klass->rank) {
1590                 int rank_reg = alloc_preg (cfg);
1591                 int eclass_reg = alloc_preg (cfg);
1592
1593                 g_assert (!klass_inst);
1594                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, rank));
1595                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
1596                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1597                 //              MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
1598                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
1599                 if (klass->cast_class == mono_defaults.object_class) {
1600                         int parent_reg = alloc_preg (cfg);
1601                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
1602                         mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, object_is_null);
1603                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1604                 } else if (klass->cast_class == mono_defaults.enum_class->parent) {
1605                         mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, object_is_null);
1606                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1607                 } else if (klass->cast_class == mono_defaults.enum_class) {
1608                         mini_emit_class_check (cfg, eclass_reg, mono_defaults.enum_class);
1609                 } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
1610                         mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, NULL, NULL);
1611                 } else {
1612                         // Pass -1 as obj_reg to skip the check below for arrays of arrays
1613                         mini_emit_castclass (cfg, -1, eclass_reg, klass->cast_class, object_is_null);
1614                 }
1615
1616                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY) && (obj_reg != -1)) {
1617                         /* Check that the object is a vector too */
1618                         int bounds_reg = alloc_preg (cfg);
1619                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
1620                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
1621                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
1622                 }
1623         } else {
1624                 int idepth_reg = alloc_preg (cfg);
1625                 int stypes_reg = alloc_preg (cfg);
1626                 int stype = alloc_preg (cfg);
1627
1628                 if (klass->idepth > MONO_DEFAULT_SUPERTABLE_SIZE) {
1629                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU2_MEMBASE, idepth_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, idepth));
1630                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, idepth_reg, klass->idepth);
1631                         MONO_EMIT_NEW_COND_EXC (cfg, LT_UN, "InvalidCastException");
1632                 }
1633                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stypes_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, supertypes));
1634                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, stype, stypes_reg, ((klass->idepth - 1) * SIZEOF_VOID_P));
1635                 mini_emit_class_check_inst (cfg, stype, klass, klass_inst);
1636         }
1637 }
1638
1639 static void
1640 mini_emit_castclass (MonoCompile *cfg, int obj_reg, int klass_reg, MonoClass *klass, MonoBasicBlock *object_is_null)
1641 {
1642         return mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, NULL, object_is_null);
1643 }
1644
1645 static void 
1646 mini_emit_memset (MonoCompile *cfg, int destreg, int offset, int size, int val, int align)
1647 {
1648         int val_reg;
1649
1650         g_assert (val == 0);
1651
1652         if (align == 0)
1653                 align = 4;
1654
1655         if ((size <= 4) && (size <= align)) {
1656                 switch (size) {
1657                 case 1:
1658                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, destreg, offset, val);
1659                         return;
1660                 case 2:
1661                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI2_MEMBASE_IMM, destreg, offset, val);
1662                         return;
1663                 case 4:
1664                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI4_MEMBASE_IMM, destreg, offset, val);
1665                         return;
1666 #if SIZEOF_REGISTER == 8
1667                 case 8:
1668                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI8_MEMBASE_IMM, destreg, offset, val);
1669                         return;
1670 #endif
1671                 }
1672         }
1673
1674         val_reg = alloc_preg (cfg);
1675
1676         if (SIZEOF_REGISTER == 8)
1677                 MONO_EMIT_NEW_I8CONST (cfg, val_reg, val);
1678         else
1679                 MONO_EMIT_NEW_ICONST (cfg, val_reg, val);
1680
1681         if (align < 4) {
1682                 /* This could be optimized further if neccesary */
1683                 while (size >= 1) {
1684                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1685                         offset += 1;
1686                         size -= 1;
1687                 }
1688                 return;
1689         }       
1690
1691 #if !NO_UNALIGNED_ACCESS
1692         if (SIZEOF_REGISTER == 8) {
1693                 if (offset % 8) {
1694                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1695                         offset += 4;
1696                         size -= 4;
1697                 }
1698                 while (size >= 8) {
1699                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, offset, val_reg);
1700                         offset += 8;
1701                         size -= 8;
1702                 }
1703         }       
1704 #endif
1705
1706         while (size >= 4) {
1707                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, val_reg);
1708                 offset += 4;
1709                 size -= 4;
1710         }
1711         while (size >= 2) {
1712                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, val_reg);
1713                 offset += 2;
1714                 size -= 2;
1715         }
1716         while (size >= 1) {
1717                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, val_reg);
1718                 offset += 1;
1719                 size -= 1;
1720         }
1721 }
1722
1723 void 
1724 mini_emit_memcpy (MonoCompile *cfg, int destreg, int doffset, int srcreg, int soffset, int size, int align)
1725 {
1726         int cur_reg;
1727
1728         if (align == 0)
1729                 align = 4;
1730
1731         /*FIXME arbitrary hack to avoid unbound code expansion.*/
1732         g_assert (size < 10000);
1733
1734         if (align < 4) {
1735                 /* This could be optimized further if neccesary */
1736                 while (size >= 1) {
1737                         cur_reg = alloc_preg (cfg);
1738                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1739                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1740                         doffset += 1;
1741                         soffset += 1;
1742                         size -= 1;
1743                 }
1744         }
1745
1746 #if !NO_UNALIGNED_ACCESS
1747         if (SIZEOF_REGISTER == 8) {
1748                 while (size >= 8) {
1749                         cur_reg = alloc_preg (cfg);
1750                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI8_MEMBASE, cur_reg, srcreg, soffset);
1751                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, destreg, doffset, cur_reg);
1752                         doffset += 8;
1753                         soffset += 8;
1754                         size -= 8;
1755                 }
1756         }       
1757 #endif
1758
1759         while (size >= 4) {
1760                 cur_reg = alloc_preg (cfg);
1761                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, cur_reg, srcreg, soffset);
1762                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, doffset, cur_reg);
1763                 doffset += 4;
1764                 soffset += 4;
1765                 size -= 4;
1766         }
1767         while (size >= 2) {
1768                 cur_reg = alloc_preg (cfg);
1769                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, cur_reg, srcreg, soffset);
1770                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, doffset, cur_reg);
1771                 doffset += 2;
1772                 soffset += 2;
1773                 size -= 2;
1774         }
1775         while (size >= 1) {
1776                 cur_reg = alloc_preg (cfg);
1777                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, cur_reg, srcreg, soffset);
1778                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, doffset, cur_reg);
1779                 doffset += 1;
1780                 soffset += 1;
1781                 size -= 1;
1782         }
1783 }
1784
1785 static int
1786 ret_type_to_call_opcode (MonoType *type, int calli, int virt, MonoGenericSharingContext *gsctx)
1787 {
1788         if (type->byref)
1789                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1790
1791 handle_enum:
1792         type = mini_get_basic_type_from_generic (gsctx, type);
1793         switch (type->type) {
1794         case MONO_TYPE_VOID:
1795                 return calli? OP_VOIDCALL_REG: virt? OP_VOIDCALLVIRT: OP_VOIDCALL;
1796         case MONO_TYPE_I1:
1797         case MONO_TYPE_U1:
1798         case MONO_TYPE_BOOLEAN:
1799         case MONO_TYPE_I2:
1800         case MONO_TYPE_U2:
1801         case MONO_TYPE_CHAR:
1802         case MONO_TYPE_I4:
1803         case MONO_TYPE_U4:
1804                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1805         case MONO_TYPE_I:
1806         case MONO_TYPE_U:
1807         case MONO_TYPE_PTR:
1808         case MONO_TYPE_FNPTR:
1809                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1810         case MONO_TYPE_CLASS:
1811         case MONO_TYPE_STRING:
1812         case MONO_TYPE_OBJECT:
1813         case MONO_TYPE_SZARRAY:
1814         case MONO_TYPE_ARRAY:    
1815                 return calli? OP_CALL_REG: virt? OP_CALLVIRT: OP_CALL;
1816         case MONO_TYPE_I8:
1817         case MONO_TYPE_U8:
1818                 return calli? OP_LCALL_REG: virt? OP_LCALLVIRT: OP_LCALL;
1819         case MONO_TYPE_R4:
1820         case MONO_TYPE_R8:
1821                 return calli? OP_FCALL_REG: virt? OP_FCALLVIRT: OP_FCALL;
1822         case MONO_TYPE_VALUETYPE:
1823                 if (type->data.klass->enumtype) {
1824                         type = mono_class_enum_basetype (type->data.klass);
1825                         goto handle_enum;
1826                 } else
1827                         return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1828         case MONO_TYPE_TYPEDBYREF:
1829                 return calli? OP_VCALL_REG: virt? OP_VCALLVIRT: OP_VCALL;
1830         case MONO_TYPE_GENERICINST:
1831                 type = &type->data.generic_class->container_class->byval_arg;
1832                 goto handle_enum;
1833         default:
1834                 g_error ("unknown type 0x%02x in ret_type_to_call_opcode", type->type);
1835         }
1836         return -1;
1837 }
1838
1839 /*
1840  * target_type_is_incompatible:
1841  * @cfg: MonoCompile context
1842  *
1843  * Check that the item @arg on the evaluation stack can be stored
1844  * in the target type (can be a local, or field, etc).
1845  * The cfg arg can be used to check if we need verification or just
1846  * validity checks.
1847  *
1848  * Returns: non-0 value if arg can't be stored on a target.
1849  */
1850 static int
1851 target_type_is_incompatible (MonoCompile *cfg, MonoType *target, MonoInst *arg)
1852 {
1853         MonoType *simple_type;
1854         MonoClass *klass;
1855
1856         if (target->byref) {
1857                 /* FIXME: check that the pointed to types match */
1858                 if (arg->type == STACK_MP)
1859                         return arg->klass != mono_class_from_mono_type (target);
1860                 if (arg->type == STACK_PTR)
1861                         return 0;
1862                 return 1;
1863         }
1864
1865         simple_type = mono_type_get_underlying_type (target);
1866         switch (simple_type->type) {
1867         case MONO_TYPE_VOID:
1868                 return 1;
1869         case MONO_TYPE_I1:
1870         case MONO_TYPE_U1:
1871         case MONO_TYPE_BOOLEAN:
1872         case MONO_TYPE_I2:
1873         case MONO_TYPE_U2:
1874         case MONO_TYPE_CHAR:
1875         case MONO_TYPE_I4:
1876         case MONO_TYPE_U4:
1877                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1878                         return 1;
1879                 return 0;
1880         case MONO_TYPE_PTR:
1881                 /* STACK_MP is needed when setting pinned locals */
1882                 if (arg->type != STACK_I4 && arg->type != STACK_PTR && arg->type != STACK_MP)
1883                         return 1;
1884                 return 0;
1885         case MONO_TYPE_I:
1886         case MONO_TYPE_U:
1887         case MONO_TYPE_FNPTR:
1888                 if (arg->type != STACK_I4 && arg->type != STACK_PTR)
1889                         return 1;
1890                 return 0;
1891         case MONO_TYPE_CLASS:
1892         case MONO_TYPE_STRING:
1893         case MONO_TYPE_OBJECT:
1894         case MONO_TYPE_SZARRAY:
1895         case MONO_TYPE_ARRAY:    
1896                 if (arg->type != STACK_OBJ)
1897                         return 1;
1898                 /* FIXME: check type compatibility */
1899                 return 0;
1900         case MONO_TYPE_I8:
1901         case MONO_TYPE_U8:
1902                 if (arg->type != STACK_I8)
1903                         return 1;
1904                 return 0;
1905         case MONO_TYPE_R4:
1906         case MONO_TYPE_R8:
1907                 if (arg->type != STACK_R8)
1908                         return 1;
1909                 return 0;
1910         case MONO_TYPE_VALUETYPE:
1911                 if (arg->type != STACK_VTYPE)
1912                         return 1;
1913                 klass = mono_class_from_mono_type (simple_type);
1914                 if (klass != arg->klass)
1915                         return 1;
1916                 return 0;
1917         case MONO_TYPE_TYPEDBYREF:
1918                 if (arg->type != STACK_VTYPE)
1919                         return 1;
1920                 klass = mono_class_from_mono_type (simple_type);
1921                 if (klass != arg->klass)
1922                         return 1;
1923                 return 0;
1924         case MONO_TYPE_GENERICINST:
1925                 if (mono_type_generic_inst_is_valuetype (simple_type)) {
1926                         if (arg->type != STACK_VTYPE)
1927                                 return 1;
1928                         klass = mono_class_from_mono_type (simple_type);
1929                         if (klass != arg->klass)
1930                                 return 1;
1931                         return 0;
1932                 } else {
1933                         if (arg->type != STACK_OBJ)
1934                                 return 1;
1935                         /* FIXME: check type compatibility */
1936                         return 0;
1937                 }
1938         case MONO_TYPE_VAR:
1939         case MONO_TYPE_MVAR:
1940                 /* FIXME: all the arguments must be references for now,
1941                  * later look inside cfg and see if the arg num is
1942                  * really a reference
1943                  */
1944                 g_assert (cfg->generic_sharing_context);
1945                 if (arg->type != STACK_OBJ)
1946                         return 1;
1947                 return 0;
1948         default:
1949                 g_error ("unknown type 0x%02x in target_type_is_incompatible", simple_type->type);
1950         }
1951         return 1;
1952 }
1953
1954 /*
1955  * Prepare arguments for passing to a function call.
1956  * Return a non-zero value if the arguments can't be passed to the given
1957  * signature.
1958  * The type checks are not yet complete and some conversions may need
1959  * casts on 32 or 64 bit architectures.
1960  *
1961  * FIXME: implement this using target_type_is_incompatible ()
1962  */
1963 static int
1964 check_call_signature (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args)
1965 {
1966         MonoType *simple_type;
1967         int i;
1968
1969         if (sig->hasthis) {
1970                 if (args [0]->type != STACK_OBJ && args [0]->type != STACK_MP && args [0]->type != STACK_PTR)
1971                         return 1;
1972                 args++;
1973         }
1974         for (i = 0; i < sig->param_count; ++i) {
1975                 if (sig->params [i]->byref) {
1976                         if (args [i]->type != STACK_MP && args [i]->type != STACK_PTR)
1977                                 return 1;
1978                         continue;
1979                 }
1980                 simple_type = sig->params [i];
1981                 simple_type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, simple_type);
1982 handle_enum:
1983                 switch (simple_type->type) {
1984                 case MONO_TYPE_VOID:
1985                         return 1;
1986                         continue;
1987                 case MONO_TYPE_I1:
1988                 case MONO_TYPE_U1:
1989                 case MONO_TYPE_BOOLEAN:
1990                 case MONO_TYPE_I2:
1991                 case MONO_TYPE_U2:
1992                 case MONO_TYPE_CHAR:
1993                 case MONO_TYPE_I4:
1994                 case MONO_TYPE_U4:
1995                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR)
1996                                 return 1;
1997                         continue;
1998                 case MONO_TYPE_I:
1999                 case MONO_TYPE_U:
2000                 case MONO_TYPE_PTR:
2001                 case MONO_TYPE_FNPTR:
2002                         if (args [i]->type != STACK_I4 && args [i]->type != STACK_PTR && args [i]->type != STACK_MP && args [i]->type != STACK_OBJ)
2003                                 return 1;
2004                         continue;
2005                 case MONO_TYPE_CLASS:
2006                 case MONO_TYPE_STRING:
2007                 case MONO_TYPE_OBJECT:
2008                 case MONO_TYPE_SZARRAY:
2009                 case MONO_TYPE_ARRAY:    
2010                         if (args [i]->type != STACK_OBJ)
2011                                 return 1;
2012                         continue;
2013                 case MONO_TYPE_I8:
2014                 case MONO_TYPE_U8:
2015                         if (args [i]->type != STACK_I8)
2016                                 return 1;
2017                         continue;
2018                 case MONO_TYPE_R4:
2019                 case MONO_TYPE_R8:
2020                         if (args [i]->type != STACK_R8)
2021                                 return 1;
2022                         continue;
2023                 case MONO_TYPE_VALUETYPE:
2024                         if (simple_type->data.klass->enumtype) {
2025                                 simple_type = mono_class_enum_basetype (simple_type->data.klass);
2026                                 goto handle_enum;
2027                         }
2028                         if (args [i]->type != STACK_VTYPE)
2029                                 return 1;
2030                         continue;
2031                 case MONO_TYPE_TYPEDBYREF:
2032                         if (args [i]->type != STACK_VTYPE)
2033                                 return 1;
2034                         continue;
2035                 case MONO_TYPE_GENERICINST:
2036                         simple_type = &simple_type->data.generic_class->container_class->byval_arg;
2037                         goto handle_enum;
2038
2039                 default:
2040                         g_error ("unknown type 0x%02x in check_call_signature",
2041                                  simple_type->type);
2042                 }
2043         }
2044         return 0;
2045 }
2046
2047 static int
2048 callvirt_to_call (int opcode)
2049 {
2050         switch (opcode) {
2051         case OP_CALLVIRT:
2052                 return OP_CALL;
2053         case OP_VOIDCALLVIRT:
2054                 return OP_VOIDCALL;
2055         case OP_FCALLVIRT:
2056                 return OP_FCALL;
2057         case OP_VCALLVIRT:
2058                 return OP_VCALL;
2059         case OP_LCALLVIRT:
2060                 return OP_LCALL;
2061         default:
2062                 g_assert_not_reached ();
2063         }
2064
2065         return -1;
2066 }
2067
2068 static int
2069 callvirt_to_call_membase (int opcode)
2070 {
2071         switch (opcode) {
2072         case OP_CALLVIRT:
2073                 return OP_CALL_MEMBASE;
2074         case OP_VOIDCALLVIRT:
2075                 return OP_VOIDCALL_MEMBASE;
2076         case OP_FCALLVIRT:
2077                 return OP_FCALL_MEMBASE;
2078         case OP_LCALLVIRT:
2079                 return OP_LCALL_MEMBASE;
2080         case OP_VCALLVIRT:
2081                 return OP_VCALL_MEMBASE;
2082         default:
2083                 g_assert_not_reached ();
2084         }
2085
2086         return -1;
2087 }
2088
2089 #ifdef MONO_ARCH_HAVE_IMT
2090 static void
2091 emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
2092 {
2093         int method_reg;
2094
2095         if (COMPILE_LLVM (cfg)) {
2096                 method_reg = alloc_preg (cfg);
2097
2098                 if (imt_arg) {
2099                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2100                 } else if (cfg->compile_aot) {
2101                         MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
2102                 } else {
2103                         MonoInst *ins;
2104                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2105                         ins->inst_p0 = call->method;
2106                         ins->dreg = method_reg;
2107                         MONO_ADD_INS (cfg->cbb, ins);
2108                 }
2109
2110 #ifdef ENABLE_LLVM
2111                 call->imt_arg_reg = method_reg;
2112 #endif
2113 #ifdef MONO_ARCH_IMT_REG
2114         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2115 #else
2116         /* Need this to keep the IMT arg alive */
2117         mono_call_inst_add_outarg_reg (cfg, call, method_reg, 0, FALSE);
2118 #endif
2119                 return;
2120         }
2121
2122 #ifdef MONO_ARCH_IMT_REG
2123         method_reg = alloc_preg (cfg);
2124
2125         if (imt_arg) {
2126                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, method_reg, imt_arg->dreg);
2127         } else if (cfg->compile_aot) {
2128                 MONO_EMIT_NEW_AOTCONST (cfg, method_reg, call->method, MONO_PATCH_INFO_METHODCONST);
2129         } else {
2130                 MonoInst *ins;
2131                 MONO_INST_NEW (cfg, ins, OP_PCONST);
2132                 ins->inst_p0 = call->method;
2133                 ins->dreg = method_reg;
2134                 MONO_ADD_INS (cfg->cbb, ins);
2135         }
2136
2137         mono_call_inst_add_outarg_reg (cfg, call, method_reg, MONO_ARCH_IMT_REG, FALSE);
2138 #else
2139         mono_arch_emit_imt_argument (cfg, call, imt_arg);
2140 #endif
2141 }
2142 #endif
2143
2144 static MonoJumpInfo *
2145 mono_patch_info_new (MonoMemPool *mp, int ip, MonoJumpInfoType type, gconstpointer target)
2146 {
2147         MonoJumpInfo *ji = mono_mempool_alloc (mp, sizeof (MonoJumpInfo));
2148
2149         ji->ip.i = ip;
2150         ji->type = type;
2151         ji->data.target = target;
2152
2153         return ji;
2154 }
2155
2156 inline static MonoCallInst *
2157 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
2158                                          MonoInst **args, int calli, int virtual, int tail)
2159 {
2160         MonoCallInst *call;
2161 #ifdef MONO_ARCH_SOFT_FLOAT
2162         int i;
2163 #endif
2164
2165         if (tail)
2166                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
2167         else
2168                 MONO_INST_NEW_CALL (cfg, call, ret_type_to_call_opcode (sig->ret, calli, virtual, cfg->generic_sharing_context));
2169
2170         call->args = args;
2171         call->signature = sig;
2172
2173         type_to_eval_stack_type ((cfg), sig->ret, &call->inst);
2174
2175         if (tail) {
2176                 if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2177                         call->vret_var = cfg->vret_addr;
2178                         //g_assert_not_reached ();
2179                 }
2180         } else if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2181                 MonoInst *temp = mono_compile_create_var (cfg, sig->ret, OP_LOCAL);
2182                 MonoInst *loada;
2183
2184                 temp->backend.is_pinvoke = sig->pinvoke;
2185
2186                 /*
2187                  * We use a new opcode OP_OUTARG_VTRETADDR instead of LDADDR for emitting the
2188                  * address of return value to increase optimization opportunities.
2189                  * Before vtype decomposition, the dreg of the call ins itself represents the
2190                  * fact the call modifies the return value. After decomposition, the call will
2191                  * be transformed into one of the OP_VOIDCALL opcodes, and the VTRETADDR opcode
2192                  * will be transformed into an LDADDR.
2193                  */
2194                 MONO_INST_NEW (cfg, loada, OP_OUTARG_VTRETADDR);
2195                 loada->dreg = alloc_preg (cfg);
2196                 loada->inst_p0 = temp;
2197                 /* We reference the call too since call->dreg could change during optimization */
2198                 loada->inst_p1 = call;
2199                 MONO_ADD_INS (cfg->cbb, loada);
2200
2201                 call->inst.dreg = temp->dreg;
2202
2203                 call->vret_var = loada;
2204         } else if (!MONO_TYPE_IS_VOID (sig->ret))
2205                 call->inst.dreg = alloc_dreg (cfg, call->inst.type);
2206
2207 #ifdef MONO_ARCH_SOFT_FLOAT
2208         if (COMPILE_SOFT_FLOAT (cfg)) {
2209                 /* 
2210                  * If the call has a float argument, we would need to do an r8->r4 conversion using 
2211                  * an icall, but that cannot be done during the call sequence since it would clobber
2212                  * the call registers + the stack. So we do it before emitting the call.
2213                  */
2214                 for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2215                         MonoType *t;
2216                         MonoInst *in = call->args [i];
2217
2218                         if (i >= sig->hasthis)
2219                                 t = sig->params [i - sig->hasthis];
2220                         else
2221                                 t = &mono_defaults.int_class->byval_arg;
2222                         t = mono_type_get_underlying_type (t);
2223
2224                         if (!t->byref && t->type == MONO_TYPE_R4) {
2225                                 MonoInst *iargs [1];
2226                                 MonoInst *conv;
2227
2228                                 iargs [0] = in;
2229                                 conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
2230
2231                                 /* The result will be in an int vreg */
2232                                 call->args [i] = conv;
2233                         }
2234                 }
2235         }
2236 #endif
2237
2238 #ifdef ENABLE_LLVM
2239         if (COMPILE_LLVM (cfg))
2240                 mono_llvm_emit_call (cfg, call);
2241         else
2242                 mono_arch_emit_call (cfg, call);
2243 #else
2244         mono_arch_emit_call (cfg, call);
2245 #endif
2246
2247         cfg->param_area = MAX (cfg->param_area, call->stack_usage);
2248         cfg->flags |= MONO_CFG_HAS_CALLS;
2249         
2250         return call;
2251 }
2252
2253 inline static MonoInst*
2254 mono_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr)
2255 {
2256         MonoCallInst *call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE);
2257
2258         call->inst.sreg1 = addr->dreg;
2259
2260         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2261
2262         return (MonoInst*)call;
2263 }
2264
2265 static void
2266 set_rgctx_arg (MonoCompile *cfg, MonoCallInst *call, int rgctx_reg, MonoInst *rgctx_arg)
2267 {
2268 #ifdef MONO_ARCH_RGCTX_REG
2269         mono_call_inst_add_outarg_reg (cfg, call, rgctx_reg, MONO_ARCH_RGCTX_REG, FALSE);
2270         cfg->uses_rgctx_reg = TRUE;
2271         call->rgctx_reg = TRUE;
2272 #ifdef ENABLE_LLVM
2273         call->rgctx_arg_reg = rgctx_reg;
2274 #endif
2275 #else
2276         NOT_IMPLEMENTED;
2277 #endif
2278 }       
2279
2280 inline static MonoInst*
2281 mono_emit_rgctx_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, MonoInst *addr, MonoInst *rgctx_arg)
2282 {
2283         MonoCallInst *call;
2284         int rgctx_reg = -1;
2285
2286         if (rgctx_arg) {
2287                 rgctx_reg = mono_alloc_preg (cfg);
2288                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, rgctx_arg->dreg);
2289         }
2290         call = (MonoCallInst*)mono_emit_calli (cfg, sig, args, addr);
2291         if (rgctx_arg)
2292                 set_rgctx_arg (cfg, call, rgctx_reg, rgctx_arg);
2293         return (MonoInst*)call;
2294 }
2295
2296 static MonoInst*
2297 emit_get_rgctx_method (MonoCompile *cfg, int context_used, MonoMethod *cmethod, int rgctx_type);
2298 static MonoInst*
2299 emit_get_rgctx_klass (MonoCompile *cfg, int context_used, MonoClass *klass, int rgctx_type);
2300
2301 static MonoInst*
2302 mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
2303                                                         MonoInst **args, MonoInst *this, MonoInst *imt_arg)
2304 {
2305         gboolean might_be_remote;
2306         gboolean virtual = this != NULL;
2307         gboolean enable_for_aot = TRUE;
2308         int context_used;
2309         MonoCallInst *call;
2310
2311         if (method->string_ctor) {
2312                 /* Create the real signature */
2313                 /* FIXME: Cache these */
2314                 MonoMethodSignature *ctor_sig = mono_metadata_signature_dup_mempool (cfg->mempool, sig);
2315                 ctor_sig->ret = &mono_defaults.string_class->byval_arg;
2316
2317                 sig = ctor_sig;
2318         }
2319
2320         might_be_remote = this && sig->hasthis &&
2321                 (method->klass->marshalbyref || method->klass == mono_defaults.object_class) &&
2322                 !(method->flags & METHOD_ATTRIBUTE_VIRTUAL) && !MONO_CHECK_THIS (this);
2323
2324         context_used = mono_method_check_context_used (method);
2325         if (might_be_remote && context_used) {
2326                 MonoInst *addr;
2327
2328                 g_assert (cfg->generic_sharing_context);
2329
2330                 addr = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_REMOTING_INVOKE_WITH_CHECK);
2331
2332                 return mono_emit_calli (cfg, sig, args, addr);
2333         }
2334
2335         call = mono_emit_call_args (cfg, sig, args, FALSE, virtual, FALSE);
2336
2337         if (might_be_remote)
2338                 call->method = mono_marshal_get_remoting_invoke_with_check (method);
2339         else
2340                 call->method = method;
2341         call->inst.flags |= MONO_INST_HAS_METHOD;
2342         call->inst.inst_left = this;
2343
2344         if (virtual) {
2345                 int vtable_reg, slot_reg, this_reg;
2346
2347                 this_reg = this->dreg;
2348
2349 #ifdef MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE
2350                 if ((method->klass->parent == mono_defaults.multicastdelegate_class) && (!strcmp (method->name, "Invoke"))) {
2351                         MONO_EMIT_NULL_CHECK (cfg, this_reg);
2352
2353                         /* Make a call to delegate->invoke_impl */
2354                         call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2355                         call->inst.inst_basereg = this_reg;
2356                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoDelegate, invoke_impl);
2357                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2358
2359                         return (MonoInst*)call;
2360                 }
2361 #endif
2362
2363                 if ((!cfg->compile_aot || enable_for_aot) && 
2364                         (!(method->flags & METHOD_ATTRIBUTE_VIRTUAL) || 
2365                          (MONO_METHOD_IS_FINAL (method) &&
2366                           method->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK)) &&
2367                         !(method->klass->marshalbyref && context_used)) {
2368                         /* 
2369                          * the method is not virtual, we just need to ensure this is not null
2370                          * and then we can call the method directly.
2371                          */
2372                         if (method->klass->marshalbyref || method->klass == mono_defaults.object_class) {
2373                                 /* 
2374                                  * The check above ensures method is not gshared, this is needed since
2375                                  * gshared methods can't have wrappers.
2376                                  */
2377                                 method = call->method = mono_marshal_get_remoting_invoke_with_check (method);
2378                         }
2379
2380                         if (!method->string_ctor)
2381                                 MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2382
2383                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2384
2385                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2386
2387                         return (MonoInst*)call;
2388                 }
2389
2390                 if ((method->flags & METHOD_ATTRIBUTE_VIRTUAL) && MONO_METHOD_IS_FINAL (method)) {
2391                         /*
2392                          * the method is virtual, but we can statically dispatch since either
2393                          * it's class or the method itself are sealed.
2394                          * But first we need to ensure it's not a null reference.
2395                          */
2396                         MONO_EMIT_NEW_CHECK_THIS (cfg, this_reg);
2397
2398                         call->inst.opcode = callvirt_to_call (call->inst.opcode);
2399                         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2400
2401                         return (MonoInst*)call;
2402                 }
2403
2404                 call->inst.opcode = callvirt_to_call_membase (call->inst.opcode);
2405
2406                 vtable_reg = alloc_preg (cfg);
2407                 MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, this_reg, G_STRUCT_OFFSET (MonoObject, vtable));
2408                 if (method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
2409                         slot_reg = -1;
2410 #ifdef MONO_ARCH_HAVE_IMT
2411                         if (mono_use_imt) {
2412                                 guint32 imt_slot = mono_method_get_imt_slot (method);
2413                                 emit_imt_argument (cfg, call, imt_arg);
2414                                 slot_reg = vtable_reg;
2415                                 call->inst.inst_offset = ((gint32)imt_slot - MONO_IMT_SIZE) * SIZEOF_VOID_P;
2416                         }
2417 #endif
2418                         if (slot_reg == -1) {
2419                                 slot_reg = alloc_preg (cfg);
2420                                 mini_emit_load_intf_reg_vtable (cfg, slot_reg, vtable_reg, method->klass);
2421                                 call->inst.inst_offset = mono_method_get_vtable_index (method) * SIZEOF_VOID_P;
2422                         }
2423                 } else {
2424                         slot_reg = vtable_reg;
2425                         call->inst.inst_offset = G_STRUCT_OFFSET (MonoVTable, vtable) +
2426                                 ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
2427 #ifdef MONO_ARCH_HAVE_IMT
2428                         if (imt_arg) {
2429                                 g_assert (mono_method_signature (method)->generic_param_count);
2430                                 emit_imt_argument (cfg, call, imt_arg);
2431                         }
2432 #endif
2433                 }
2434
2435                 call->inst.sreg1 = slot_reg;
2436                 call->virtual = TRUE;
2437         }
2438
2439         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2440
2441         return (MonoInst*)call;
2442 }
2443
2444 static MonoInst*
2445 mono_emit_rgctx_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSignature *sig,
2446                 MonoInst **args, MonoInst *this, MonoInst *imt_arg, MonoInst *vtable_arg)
2447 {
2448         int rgctx_reg = 0;
2449         MonoInst *ins;
2450         MonoCallInst *call;
2451
2452         if (vtable_arg) {
2453                 rgctx_reg = mono_alloc_preg (cfg);
2454                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
2455         }
2456         ins = mono_emit_method_call_full (cfg, method, sig, args, this, imt_arg);
2457
2458         call = (MonoCallInst*)ins;
2459         if (vtable_arg)
2460                 set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg);
2461
2462         return ins;
2463 }
2464
2465 MonoInst*
2466 mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this)
2467 {
2468         return mono_emit_method_call_full (cfg, method, mono_method_signature (method), args, this, NULL);
2469 }
2470
2471 MonoInst*
2472 mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig,
2473                                            MonoInst **args)
2474 {
2475         MonoCallInst *call;
2476
2477         g_assert (sig);
2478
2479         call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE);
2480         call->fptr = func;
2481
2482         MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
2483
2484         return (MonoInst*)call;
2485 }
2486
2487 MonoInst*
2488 mono_emit_jit_icall (MonoCompile *cfg, gconstpointer func, MonoInst **args)
2489 {
2490         MonoJitICallInfo *info = mono_find_jit_icall_by_addr (func);
2491
2492         g_assert (info);
2493
2494         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, args);
2495 }
2496
2497 /*
2498  * mono_emit_abs_call:
2499  *
2500  *   Emit a call to the runtime function described by PATCH_TYPE and DATA.
2501  */
2502 inline static MonoInst*
2503 mono_emit_abs_call (MonoCompile *cfg, MonoJumpInfoType patch_type, gconstpointer data, 
2504                                         MonoMethodSignature *sig, MonoInst **args)
2505 {
2506         MonoJumpInfo *ji = mono_patch_info_new (cfg->mempool, 0, patch_type, data);
2507         MonoInst *ins;
2508
2509         /* 
2510          * We pass ji as the call address, the PATCH_INFO_ABS resolving code will
2511          * handle it.
2512          */
2513         if (cfg->abs_patches == NULL)
2514                 cfg->abs_patches = g_hash_table_new (NULL, NULL);
2515         g_hash_table_insert (cfg->abs_patches, ji, ji);
2516         ins = mono_emit_native_call (cfg, ji, sig, args);
2517         ((MonoCallInst*)ins)->fptr_is_patch = TRUE;
2518         return ins;
2519 }
2520  
2521 static MonoInst*
2522 mono_emit_widen_call_res (MonoCompile *cfg, MonoInst *ins, MonoMethodSignature *fsig)
2523 {
2524         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
2525                 if ((fsig->pinvoke || LLVM_ENABLED) && !fsig->ret->byref) {
2526                         int widen_op = -1;
2527
2528                         /* 
2529                          * Native code might return non register sized integers 
2530                          * without initializing the upper bits.
2531                          */
2532                         switch (mono_type_to_load_membase (cfg, fsig->ret)) {
2533                         case OP_LOADI1_MEMBASE:
2534                                 widen_op = OP_ICONV_TO_I1;
2535                                 break;
2536                         case OP_LOADU1_MEMBASE:
2537                                 widen_op = OP_ICONV_TO_U1;
2538                                 break;
2539                         case OP_LOADI2_MEMBASE:
2540                                 widen_op = OP_ICONV_TO_I2;
2541                                 break;
2542                         case OP_LOADU2_MEMBASE:
2543                                 widen_op = OP_ICONV_TO_U2;
2544                                 break;
2545                         default:
2546                                 break;
2547                         }
2548
2549                         if (widen_op != -1) {
2550                                 int dreg = alloc_preg (cfg);
2551                                 MonoInst *widen;
2552
2553                                 EMIT_NEW_UNALU (cfg, widen, widen_op, dreg, ins->dreg);
2554                                 widen->type = ins->type;
2555                                 ins = widen;
2556                         }
2557                 }
2558         }
2559
2560         return ins;
2561 }
2562
2563 static MonoMethod*
2564 get_memcpy_method (void)
2565 {
2566         static MonoMethod *memcpy_method = NULL;
2567         if (!memcpy_method) {
2568                 memcpy_method = mono_class_get_method_from_name (mono_defaults.string_class, "memcpy", 3);
2569                 if (!memcpy_method)
2570                         g_error ("Old corlib found. Install a new one");
2571         }
2572         return memcpy_method;
2573 }
2574
2575 static void
2576 create_write_barrier_bitmap (MonoClass *klass, unsigned *wb_bitmap, int offset)
2577 {
2578         MonoClassField *field;
2579         gpointer iter = NULL;
2580
2581         while ((field = mono_class_get_fields (klass, &iter))) {
2582                 int foffset;
2583
2584                 if (field->type->attrs & FIELD_ATTRIBUTE_STATIC)
2585                         continue;
2586                 foffset = klass->valuetype ? field->offset - sizeof (MonoObject): field->offset;
2587                 if (mono_type_is_reference (field->type)) {
2588                         g_assert ((foffset % SIZEOF_VOID_P) == 0);
2589                         *wb_bitmap |= 1 << ((offset + foffset) / SIZEOF_VOID_P);
2590                 } else {
2591                         /*FIXME support nested value types so this works for: struct X { Y y; int z;} struct Y { object a,b; }*/
2592                         MonoClass *field_class = mono_class_from_mono_type (field->type);
2593                         if (field_class->has_references)
2594                                 create_write_barrier_bitmap (field_class, wb_bitmap, offset + foffset);
2595                 }
2596         }
2597 }
2598
2599 static void
2600 emit_write_barrier (MonoCompile *cfg, MonoInst *ptr, MonoInst *value, int value_reg)
2601 {
2602         int card_table_shift_bits;
2603         gpointer card_table_mask;
2604         guint8 *card_table;
2605         MonoInst *dummy_use;
2606         int nursery_shift_bits;
2607         size_t nursery_size;
2608         gboolean has_card_table_wb = FALSE;
2609
2610         if (!cfg->gen_write_barriers)
2611                 return;
2612
2613         card_table = mono_gc_get_card_table (&card_table_shift_bits, &card_table_mask);
2614
2615         mono_gc_get_nursery (&nursery_shift_bits, &nursery_size);
2616
2617 #ifdef MONO_ARCH_HAVE_CARD_TABLE_WBARRIER
2618         has_card_table_wb = TRUE;
2619 #endif
2620
2621         if (has_card_table_wb && !cfg->compile_aot && card_table && nursery_shift_bits > 0) {
2622                 MonoInst *wbarrier;
2623
2624                 MONO_INST_NEW (cfg, wbarrier, OP_CARD_TABLE_WBARRIER);
2625                 wbarrier->sreg1 = ptr->dreg;
2626                 if (value)
2627                         wbarrier->sreg2 = value->dreg;
2628                 else
2629                         wbarrier->sreg2 = value_reg;
2630                 MONO_ADD_INS (cfg->cbb, wbarrier);
2631         } else if (card_table) {
2632                 int offset_reg = alloc_preg (cfg);
2633                 int card_reg  = alloc_preg (cfg);
2634                 MonoInst *ins;
2635
2636                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHR_UN_IMM, offset_reg, ptr->dreg, card_table_shift_bits);
2637                 if (card_table_mask)
2638                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PAND_IMM, offset_reg, offset_reg, card_table_mask);
2639
2640                 /*We can't use PADD_IMM since the cardtable might end up in high addresses and amd64 doesn't support
2641                  * IMM's larger than 32bits.
2642                  */
2643                 if (cfg->compile_aot) {
2644                         MONO_EMIT_NEW_AOTCONST (cfg, card_reg, NULL, MONO_PATCH_INFO_GC_CARD_TABLE_ADDR);
2645                 } else {
2646                         MONO_INST_NEW (cfg, ins, OP_PCONST);
2647                         ins->inst_p0 = card_table;
2648                         ins->dreg = card_reg;
2649                         MONO_ADD_INS (cfg->cbb, ins);
2650                 }
2651
2652                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, offset_reg, offset_reg, card_reg);
2653                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREI1_MEMBASE_IMM, offset_reg, 0, 1);
2654         } else {
2655                 MonoMethod *write_barrier = mono_gc_get_write_barrier ();
2656                 mono_emit_method_call (cfg, write_barrier, &ptr, NULL);
2657         }
2658
2659         if (value) {
2660                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, value);
2661         } else {
2662                 MONO_INST_NEW (cfg, dummy_use, OP_DUMMY_USE);
2663                 dummy_use->sreg1 = value_reg;
2664                 MONO_ADD_INS (cfg->cbb, dummy_use);
2665         }
2666 }
2667
2668 static gboolean
2669 mono_emit_wb_aware_memcpy (MonoCompile *cfg, MonoClass *klass, MonoInst *iargs[4], int size, int align)
2670 {
2671         int dest_ptr_reg, tmp_reg, destreg, srcreg, offset;
2672         unsigned need_wb = 0;
2673
2674         if (align == 0)
2675                 align = 4;
2676
2677         /*types with references can't have alignment smaller than sizeof(void*) */
2678         if (align < SIZEOF_VOID_P)
2679                 return FALSE;
2680
2681         /*This value cannot be bigger than 32 due to the way we calculate the required wb bitmap.*/
2682         if (size > 32 * SIZEOF_VOID_P)
2683                 return FALSE;
2684
2685         create_write_barrier_bitmap (klass, &need_wb, 0);
2686
2687         /* We don't unroll more than 5 stores to avoid code bloat. */
2688         if (size > 5 * SIZEOF_VOID_P) {
2689                 /*This is harmless and simplify mono_gc_wbarrier_value_copy_bitmap */
2690                 size += (SIZEOF_VOID_P - 1);
2691                 size &= ~(SIZEOF_VOID_P - 1);
2692
2693                 EMIT_NEW_ICONST (cfg, iargs [2], size);
2694                 EMIT_NEW_ICONST (cfg, iargs [3], need_wb);
2695                 mono_emit_jit_icall (cfg, mono_gc_wbarrier_value_copy_bitmap, iargs);
2696                 return TRUE;
2697         }
2698
2699         destreg = iargs [0]->dreg;
2700         srcreg = iargs [1]->dreg;
2701         offset = 0;
2702
2703         dest_ptr_reg = alloc_preg (cfg);
2704         tmp_reg = alloc_preg (cfg);
2705
2706         /*tmp = dreg*/
2707         EMIT_NEW_UNALU (cfg, iargs [0], OP_MOVE, dest_ptr_reg, destreg);
2708
2709         while (size >= SIZEOF_VOID_P) {
2710                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, tmp_reg, srcreg, offset);
2711                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, dest_ptr_reg, 0, tmp_reg);
2712
2713                 if (need_wb & 0x1)
2714                         emit_write_barrier (cfg, iargs [0], NULL, tmp_reg);
2715
2716                 offset += SIZEOF_VOID_P;
2717                 size -= SIZEOF_VOID_P;
2718                 need_wb >>= 1;
2719
2720                 /*tmp += sizeof (void*)*/
2721                 if (size >= SIZEOF_VOID_P) {
2722                         NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, dest_ptr_reg, dest_ptr_reg, SIZEOF_VOID_P);
2723                         MONO_ADD_INS (cfg->cbb, iargs [0]);
2724                 }
2725         }
2726
2727         /* Those cannot be references since size < sizeof (void*) */
2728         while (size >= 4) {
2729                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, tmp_reg, srcreg, offset);
2730                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, destreg, offset, tmp_reg);
2731                 offset += 4;
2732                 size -= 4;
2733         }
2734
2735         while (size >= 2) {
2736                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI2_MEMBASE, tmp_reg, srcreg, offset);
2737                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, destreg, offset, tmp_reg);
2738                 offset += 2;
2739                 size -= 2;
2740         }
2741
2742         while (size >= 1) {
2743                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI1_MEMBASE, tmp_reg, srcreg, offset);
2744                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI1_MEMBASE_REG, destreg, offset, tmp_reg);
2745                 offset += 1;
2746                 size -= 1;
2747         }
2748
2749         return TRUE;
2750 }
2751
2752 /*
2753  * Emit code to copy a valuetype of type @klass whose address is stored in
2754  * @src->dreg to memory whose address is stored at @dest->dreg.
2755  */
2756 void
2757 mini_emit_stobj (MonoCompile *cfg, MonoInst *dest, MonoInst *src, MonoClass *klass, gboolean native)
2758 {
2759         MonoInst *iargs [4];
2760         int n;
2761         guint32 align = 0;
2762         MonoMethod *memcpy_method;
2763
2764         g_assert (klass);
2765         /*
2766          * This check breaks with spilled vars... need to handle it during verification anyway.
2767          * g_assert (klass && klass == src->klass && klass == dest->klass);
2768          */
2769
2770         if (native)
2771                 n = mono_class_native_size (klass, &align);
2772         else
2773                 n = mono_class_value_size (klass, &align);
2774
2775         /* if native is true there should be no references in the struct */
2776         if (cfg->gen_write_barriers && klass->has_references && !native) {
2777                 /* Avoid barriers when storing to the stack */
2778                 if (!((dest->opcode == OP_ADD_IMM && dest->sreg1 == cfg->frame_reg) ||
2779                           (dest->opcode == OP_LDADDR))) {
2780                         int context_used = 0;
2781
2782                         iargs [0] = dest;
2783                         iargs [1] = src;
2784
2785                         if (cfg->generic_sharing_context)
2786                                 context_used = mono_class_check_context_used (klass);
2787
2788                         /* It's ok to intrinsify under gsharing since shared code types are layout stable. */
2789                         if ((cfg->opt & MONO_OPT_INTRINS) && mono_emit_wb_aware_memcpy (cfg, klass, iargs, n, align)) {
2790                                 return;
2791                         } else if (context_used) {
2792                                 iargs [2] = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
2793                         }  else {
2794                                 if (cfg->compile_aot) {
2795                                         EMIT_NEW_CLASSCONST (cfg, iargs [2], klass);
2796                                 } else {
2797                                         EMIT_NEW_PCONST (cfg, iargs [2], klass);
2798                                         mono_class_compute_gc_descriptor (klass);
2799                                 }
2800                         }
2801
2802                         mono_emit_jit_icall (cfg, mono_value_copy, iargs);
2803                         return;
2804                 }
2805         }
2806
2807         if ((cfg->opt & MONO_OPT_INTRINS) && n <= sizeof (gpointer) * 5) {
2808                 /* FIXME: Optimize the case when src/dest is OP_LDADDR */
2809                 mini_emit_memcpy (cfg, dest->dreg, 0, src->dreg, 0, n, align);
2810         } else {
2811                 iargs [0] = dest;
2812                 iargs [1] = src;
2813                 EMIT_NEW_ICONST (cfg, iargs [2], n);
2814                 
2815                 memcpy_method = get_memcpy_method ();
2816                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
2817         }
2818 }
2819
2820 static MonoMethod*
2821 get_memset_method (void)
2822 {
2823         static MonoMethod *memset_method = NULL;
2824         if (!memset_method) {
2825                 memset_method = mono_class_get_method_from_name (mono_defaults.string_class, "memset", 3);
2826                 if (!memset_method)
2827                         g_error ("Old corlib found. Install a new one");
2828         }
2829         return memset_method;
2830 }
2831
2832 void
2833 mini_emit_initobj (MonoCompile *cfg, MonoInst *dest, const guchar *ip, MonoClass *klass)
2834 {
2835         MonoInst *iargs [3];
2836         int n;
2837         guint32 align;
2838         MonoMethod *memset_method;
2839
2840         /* FIXME: Optimize this for the case when dest is an LDADDR */
2841
2842         mono_class_init (klass);
2843         n = mono_class_value_size (klass, &align);
2844
2845         if (n <= sizeof (gpointer) * 5) {
2846                 mini_emit_memset (cfg, dest->dreg, 0, n, 0, align);
2847         }
2848         else {
2849                 memset_method = get_memset_method ();
2850                 iargs [0] = dest;
2851                 EMIT_NEW_ICONST (cfg, iargs [1], 0);
2852                 EMIT_NEW_ICONST (cfg, iargs [2], n);
2853                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
2854         }
2855 }
2856
2857 static MonoInst*
2858 emit_get_rgctx (MonoCompile *cfg, MonoMethod *method, int context_used)
2859 {
2860         MonoInst *this = NULL;
2861
2862         g_assert (cfg->generic_sharing_context);
2863
2864         if (!(method->flags & METHOD_ATTRIBUTE_STATIC) &&
2865                         !(context_used & MONO_GENERIC_CONTEXT_USED_METHOD) &&
2866                         !method->klass->valuetype)
2867                 EMIT_NEW_ARGLOAD (cfg, this, 0);
2868
2869         if (context_used & MONO_GENERIC_CONTEXT_USED_METHOD) {
2870                 MonoInst *mrgctx_loc, *mrgctx_var;
2871
2872                 g_assert (!this);
2873                 g_assert (method->is_inflated && mono_method_get_context (method)->method_inst);
2874
2875                 mrgctx_loc = mono_get_vtable_var (cfg);
2876                 EMIT_NEW_TEMPLOAD (cfg, mrgctx_var, mrgctx_loc->inst_c0);
2877
2878                 return mrgctx_var;
2879         } else if (method->flags & METHOD_ATTRIBUTE_STATIC || method->klass->valuetype) {
2880                 MonoInst *vtable_loc, *vtable_var;
2881
2882                 g_assert (!this);
2883
2884                 vtable_loc = mono_get_vtable_var (cfg);
2885                 EMIT_NEW_TEMPLOAD (cfg, vtable_var, vtable_loc->inst_c0);
2886
2887                 if (method->is_inflated && mono_method_get_context (method)->method_inst) {
2888                         MonoInst *mrgctx_var = vtable_var;
2889                         int vtable_reg;
2890
2891                         vtable_reg = alloc_preg (cfg);
2892                         EMIT_NEW_LOAD_MEMBASE (cfg, vtable_var, OP_LOAD_MEMBASE, vtable_reg, mrgctx_var->dreg, G_STRUCT_OFFSET (MonoMethodRuntimeGenericContext, class_vtable));
2893                         vtable_var->type = STACK_PTR;
2894                 }
2895
2896                 return vtable_var;
2897         } else {
2898                 MonoInst *ins;
2899                 int vtable_reg, res_reg;
2900         
2901                 vtable_reg = alloc_preg (cfg);
2902                 res_reg = alloc_preg (cfg);
2903                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, vtable_reg, this->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
2904                 return ins;
2905         }
2906 }
2907
2908 static MonoJumpInfoRgctxEntry *
2909 mono_patch_info_rgctx_entry_new (MonoMemPool *mp, MonoMethod *method, gboolean in_mrgctx, MonoJumpInfoType patch_type, gconstpointer patch_data, int info_type)
2910 {
2911         MonoJumpInfoRgctxEntry *res = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfoRgctxEntry));
2912         res->method = method;
2913         res->in_mrgctx = in_mrgctx;
2914         res->data = mono_mempool_alloc0 (mp, sizeof (MonoJumpInfo));
2915         res->data->type = patch_type;
2916         res->data->data.target = patch_data;
2917         res->info_type = info_type;
2918
2919         return res;
2920 }
2921
2922 static inline MonoInst*
2923 emit_rgctx_fetch (MonoCompile *cfg, MonoInst *rgctx, MonoJumpInfoRgctxEntry *entry)
2924 {
2925         return mono_emit_abs_call (cfg, MONO_PATCH_INFO_RGCTX_FETCH, entry, helper_sig_rgctx_lazy_fetch_trampoline, &rgctx);
2926 }
2927
2928 static MonoInst*
2929 emit_get_rgctx_klass (MonoCompile *cfg, int context_used,
2930                                           MonoClass *klass, int rgctx_type)
2931 {
2932         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);
2933         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
2934
2935         return emit_rgctx_fetch (cfg, rgctx, entry);
2936 }
2937
2938 /*
2939  * emit_get_rgctx_method:
2940  *
2941  *   Emit IR to load the property RGCTX_TYPE of CMETHOD. If context_used is 0, emit
2942  * normal constants, else emit a load from the rgctx.
2943  */
2944 static MonoInst*
2945 emit_get_rgctx_method (MonoCompile *cfg, int context_used,
2946                                            MonoMethod *cmethod, int rgctx_type)
2947 {
2948         if (!context_used) {
2949                 MonoInst *ins;
2950
2951                 switch (rgctx_type) {
2952                 case MONO_RGCTX_INFO_METHOD:
2953                         EMIT_NEW_METHODCONST (cfg, ins, cmethod);
2954                         return ins;
2955                 case MONO_RGCTX_INFO_METHOD_RGCTX:
2956                         EMIT_NEW_METHOD_RGCTX_CONST (cfg, ins, cmethod);
2957                         return ins;
2958                 default:
2959                         g_assert_not_reached ();
2960                 }
2961         } else {
2962                 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);
2963                 MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
2964
2965                 return emit_rgctx_fetch (cfg, rgctx, entry);
2966         }
2967 }
2968
2969 static MonoInst*
2970 emit_get_rgctx_field (MonoCompile *cfg, int context_used,
2971                                           MonoClassField *field, int rgctx_type)
2972 {
2973         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);
2974         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
2975
2976         return emit_rgctx_fetch (cfg, rgctx, entry);
2977 }
2978
2979 /*
2980  * On return the caller must check @klass for load errors.
2981  */
2982 static void
2983 emit_generic_class_init (MonoCompile *cfg, MonoClass *klass)
2984 {
2985         MonoInst *vtable_arg;
2986         MonoCallInst *call;
2987         int context_used = 0;
2988
2989         if (cfg->generic_sharing_context)
2990                 context_used = mono_class_check_context_used (klass);
2991
2992         if (context_used) {
2993                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
2994                                                                                    klass, MONO_RGCTX_INFO_VTABLE);
2995         } else {
2996                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
2997
2998                 if (!vtable)
2999                         return;
3000                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
3001         }
3002
3003         if (COMPILE_LLVM (cfg))
3004                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline_llvm, &vtable_arg);
3005         else
3006                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_GENERIC_CLASS_INIT, NULL, helper_sig_generic_class_init_trampoline, &vtable_arg);
3007 #ifdef MONO_ARCH_VTABLE_REG
3008         mono_call_inst_add_outarg_reg (cfg, call, vtable_arg->dreg, MONO_ARCH_VTABLE_REG, FALSE);
3009         cfg->uses_vtable_reg = TRUE;
3010 #else
3011         NOT_IMPLEMENTED;
3012 #endif
3013 }
3014
3015 static void
3016 save_cast_details (MonoCompile *cfg, MonoClass *klass, int obj_reg)
3017 {
3018         if (mini_get_debug_options ()->better_cast_details) {
3019                 int to_klass_reg = alloc_preg (cfg);
3020                 int vtable_reg = alloc_preg (cfg);
3021                 int klass_reg = alloc_preg (cfg);
3022                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3023
3024                 if (!tls_get) {
3025                         fprintf (stderr, "error: --debug=casts not supported on this platform.\n.");
3026                         exit (1);
3027                 }
3028
3029                 MONO_ADD_INS (cfg->cbb, tls_get);
3030                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3031                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3032
3033                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), klass_reg);
3034                 MONO_EMIT_NEW_PCONST (cfg, to_klass_reg, klass);
3035                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_to), to_klass_reg);
3036         }
3037 }
3038
3039 static void
3040 reset_cast_details (MonoCompile *cfg)
3041 {
3042         /* Reset the variables holding the cast details */
3043         if (mini_get_debug_options ()->better_cast_details) {
3044                 MonoInst *tls_get = mono_get_jit_tls_intrinsic (cfg);
3045
3046                 MONO_ADD_INS (cfg->cbb, tls_get);
3047                 /* It is enough to reset the from field */
3048                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, tls_get->dreg, G_STRUCT_OFFSET (MonoJitTlsData, class_cast_from), 0);
3049         }
3050 }
3051
3052 /*
3053  * On return the caller must check @array_class for load errors
3054  */
3055 static void
3056 mini_emit_check_array_type (MonoCompile *cfg, MonoInst *obj, MonoClass *array_class)
3057 {
3058         int vtable_reg = alloc_preg (cfg);
3059         int context_used = 0;
3060
3061         if (cfg->generic_sharing_context)
3062                 context_used = mono_class_check_context_used (array_class);
3063
3064         save_cast_details (cfg, array_class, obj->dreg);
3065
3066         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
3067
3068         if (cfg->opt & MONO_OPT_SHARED) {
3069                 int class_reg = alloc_preg (cfg);
3070                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, class_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3071                 if (cfg->compile_aot) {
3072                         int klass_reg = alloc_preg (cfg);
3073                         MONO_EMIT_NEW_CLASSCONST (cfg, klass_reg, array_class);
3074                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, class_reg, klass_reg);
3075                 } else {
3076                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, class_reg, array_class);
3077                 }
3078         } else if (context_used) {
3079                 MonoInst *vtable_ins;
3080
3081                 vtable_ins = emit_get_rgctx_klass (cfg, context_used, array_class, MONO_RGCTX_INFO_VTABLE);
3082                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vtable_ins->dreg);
3083         } else {
3084                 if (cfg->compile_aot) {
3085                         int vt_reg;
3086                         MonoVTable *vtable;
3087
3088                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3089                                 return;
3090                         vt_reg = alloc_preg (cfg);
3091                         MONO_EMIT_NEW_VTABLECONST (cfg, vt_reg, vtable);
3092                         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, vtable_reg, vt_reg);
3093                 } else {
3094                         MonoVTable *vtable;
3095                         if (!(vtable = mono_class_vtable (cfg->domain, array_class)))
3096                                 return;
3097                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vtable);
3098                 }
3099         }
3100         
3101         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "ArrayTypeMismatchException");
3102
3103         reset_cast_details (cfg);
3104 }
3105
3106 /**
3107  * Handles unbox of a Nullable<T>. If context_used is non zero, then shared 
3108  * generic code is generated.
3109  */
3110 static MonoInst*
3111 handle_unbox_nullable (MonoCompile* cfg, MonoInst* val, MonoClass* klass, int context_used)
3112 {
3113         MonoMethod* method = mono_class_get_method_from_name (klass, "Unbox", 1);
3114
3115         if (context_used) {
3116                 MonoInst *rgctx, *addr;
3117
3118                 /* FIXME: What if the class is shared?  We might not
3119                    have to get the address of the method from the
3120                    RGCTX. */
3121                 addr = emit_get_rgctx_method (cfg, context_used, method,
3122                                                                           MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3123
3124                 rgctx = emit_get_rgctx (cfg, method, context_used);
3125
3126                 return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
3127         } else {
3128                 return mono_emit_method_call (cfg, method, &val, NULL);
3129         }
3130 }
3131
3132 static MonoInst*
3133 handle_unbox (MonoCompile *cfg, MonoClass *klass, MonoInst **sp, int context_used)
3134 {
3135         MonoInst *add;
3136         int obj_reg;
3137         int vtable_reg = alloc_dreg (cfg ,STACK_PTR);
3138         int klass_reg = alloc_dreg (cfg ,STACK_PTR);
3139         int eclass_reg = alloc_dreg (cfg ,STACK_PTR);
3140         int rank_reg = alloc_dreg (cfg ,STACK_I4);
3141
3142         obj_reg = sp [0]->dreg;
3143         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3144         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3145
3146         /* FIXME: generics */
3147         g_assert (klass->rank == 0);
3148                         
3149         // Check rank == 0
3150         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, 0);
3151         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3152
3153         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3154         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, element_class));
3155
3156         if (context_used) {
3157                 MonoInst *element_class;
3158
3159                 /* This assertion is from the unboxcast insn */
3160                 g_assert (klass->rank == 0);
3161
3162                 element_class = emit_get_rgctx_klass (cfg, context_used,
3163                                 klass->element_class, MONO_RGCTX_INFO_KLASS);
3164
3165                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, eclass_reg, element_class->dreg);
3166                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3167         } else {
3168                 save_cast_details (cfg, klass->element_class, obj_reg);
3169                 mini_emit_class_check (cfg, eclass_reg, klass->element_class);
3170                 reset_cast_details (cfg);
3171         }
3172
3173         NEW_BIALU_IMM (cfg, add, OP_ADD_IMM, alloc_dreg (cfg, STACK_PTR), obj_reg, sizeof (MonoObject));
3174         MONO_ADD_INS (cfg->cbb, add);
3175         add->type = STACK_MP;
3176         add->klass = klass;
3177
3178         return add;
3179 }
3180
3181 /*
3182  * Returns NULL and set the cfg exception on error.
3183  */
3184 static MonoInst*
3185 handle_alloc (MonoCompile *cfg, MonoClass *klass, gboolean for_box, int context_used)
3186 {
3187         MonoInst *iargs [2];
3188         void *alloc_ftn;
3189
3190         if (context_used) {
3191                 MonoInst *data;
3192                 int rgctx_info;
3193                 MonoInst *iargs [2];
3194
3195                 /*
3196                   FIXME: we cannot get managed_alloc here because we can't get
3197                   the class's vtable (because it's not a closed class)
3198
3199                   MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3200                   MonoMethod *managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3201                 */
3202
3203                 if (cfg->opt & MONO_OPT_SHARED)
3204                         rgctx_info = MONO_RGCTX_INFO_KLASS;
3205                 else
3206                         rgctx_info = MONO_RGCTX_INFO_VTABLE;
3207                 data = emit_get_rgctx_klass (cfg, context_used, klass, rgctx_info);
3208
3209                 if (cfg->opt & MONO_OPT_SHARED) {
3210                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3211                         iargs [1] = data;
3212                         alloc_ftn = mono_object_new;
3213                 } else {
3214                         iargs [0] = data;
3215                         alloc_ftn = mono_object_new_specific;
3216                 }
3217
3218                 return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3219         }
3220
3221         if (cfg->opt & MONO_OPT_SHARED) {
3222                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
3223                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
3224
3225                 alloc_ftn = mono_object_new;
3226         } else if (cfg->compile_aot && cfg->cbb->out_of_line && klass->type_token && klass->image == mono_defaults.corlib && !klass->generic_class) {
3227                 /* This happens often in argument checking code, eg. throw new FooException... */
3228                 /* Avoid relocations and save some space by calling a helper function specialized to mscorlib */
3229                 EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (klass->type_token));
3230                 return mono_emit_jit_icall (cfg, mono_helper_newobj_mscorlib, iargs);
3231         } else {
3232                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
3233                 MonoMethod *managed_alloc = NULL;
3234                 gboolean pass_lw;
3235
3236                 if (!vtable) {
3237                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3238                         cfg->exception_ptr = klass;
3239                         return NULL;
3240                 }
3241
3242 #ifndef MONO_CROSS_COMPILE
3243                 managed_alloc = mono_gc_get_managed_allocator (vtable, for_box);
3244 #endif
3245
3246                 if (managed_alloc) {
3247                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3248                         return mono_emit_method_call (cfg, managed_alloc, iargs, NULL);
3249                 }
3250                 alloc_ftn = mono_class_get_allocation_ftn (vtable, for_box, &pass_lw);
3251                 if (pass_lw) {
3252                         guint32 lw = vtable->klass->instance_size;
3253                         lw = ((lw + (sizeof (gpointer) - 1)) & ~(sizeof (gpointer) - 1)) / sizeof (gpointer);
3254                         EMIT_NEW_ICONST (cfg, iargs [0], lw);
3255                         EMIT_NEW_VTABLECONST (cfg, iargs [1], vtable);
3256                 }
3257                 else {
3258                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
3259                 }
3260         }
3261
3262         return mono_emit_jit_icall (cfg, alloc_ftn, iargs);
3263 }
3264         
3265 /*
3266  * Returns NULL and set the cfg exception on error.
3267  */     
3268 static MonoInst*
3269 handle_box (MonoCompile *cfg, MonoInst *val, MonoClass *klass, int context_used)
3270 {
3271         MonoInst *alloc, *ins;
3272
3273         if (mono_class_is_nullable (klass)) {
3274                 MonoMethod* method = mono_class_get_method_from_name (klass, "Box", 1);
3275
3276                 if (context_used) {
3277                         /* FIXME: What if the class is shared?  We might not
3278                            have to get the method address from the RGCTX. */
3279                         MonoInst *addr = emit_get_rgctx_method (cfg, context_used, method,
3280                                                                                                         MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
3281                         MonoInst *rgctx = emit_get_rgctx (cfg, cfg->current_method, context_used);
3282
3283                         return mono_emit_rgctx_calli (cfg, mono_method_signature (method), &val, addr, rgctx);
3284                 } else {
3285                         return mono_emit_method_call (cfg, method, &val, NULL);
3286                 }
3287         }
3288
3289         alloc = handle_alloc (cfg, klass, TRUE, context_used);
3290         if (!alloc)
3291                 return NULL;
3292
3293         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, alloc->dreg, sizeof (MonoObject), val->dreg);
3294
3295         return alloc;
3296 }
3297
3298
3299 static gboolean
3300 mini_class_has_reference_variant_generic_argument (MonoClass *klass, int context_used)
3301 {
3302         int i;
3303         MonoGenericContainer *container;
3304         MonoGenericInst *ginst;
3305
3306         if (klass->generic_class) {
3307                 container = klass->generic_class->container_class->generic_container;
3308                 ginst = klass->generic_class->context.class_inst;
3309         } else if (klass->generic_container && context_used) {
3310                 container = klass->generic_container;
3311                 ginst = container->context.class_inst;
3312         } else {
3313                 return FALSE;
3314         }
3315
3316         for (i = 0; i < container->type_argc; ++i) {
3317                 MonoType *type;
3318                 if (!(mono_generic_container_get_param_info (container, i)->flags & (MONO_GEN_PARAM_VARIANT|MONO_GEN_PARAM_COVARIANT)))
3319                         continue;
3320                 type = ginst->type_argv [i];
3321                 if (MONO_TYPE_IS_REFERENCE (type))
3322                         return TRUE;
3323
3324                 if (context_used && (type->type == MONO_TYPE_VAR || type->type == MONO_TYPE_MVAR))
3325                         return TRUE;
3326         }
3327         return FALSE;
3328 }
3329
3330 // FIXME: This doesn't work yet (class libs tests fail?)
3331 #define is_complex_isinst(klass) (TRUE || (klass->flags & TYPE_ATTRIBUTE_INTERFACE) || klass->rank || mono_class_is_nullable (klass) || klass->marshalbyref || (klass->flags & TYPE_ATTRIBUTE_SEALED) || klass->byval_arg.type == MONO_TYPE_VAR || klass->byval_arg.type == MONO_TYPE_MVAR)
3332
3333 /*
3334  * Returns NULL and set the cfg exception on error.
3335  */
3336 static MonoInst*
3337 handle_castclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3338 {
3339         MonoBasicBlock *is_null_bb;
3340         int obj_reg = src->dreg;
3341         int vtable_reg = alloc_preg (cfg);
3342         MonoInst *klass_inst = NULL;
3343
3344         if (context_used) {
3345                 MonoInst *args [3];
3346
3347                 if(mini_class_has_reference_variant_generic_argument (klass, context_used)) {
3348                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
3349                         MonoInst *cache_ins;
3350
3351                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
3352
3353                         /* obj */
3354                         args [0] = src;
3355
3356                         /* klass - it's the second element of the cache entry*/
3357                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
3358
3359                         /* cache */
3360                         args [2] = cache_ins;
3361
3362                         return mono_emit_method_call (cfg, mono_castclass, args, NULL);
3363                 }
3364
3365                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3366
3367                 if (is_complex_isinst (klass)) {
3368                         /* Complex case, handle by an icall */
3369
3370                         /* obj */
3371                         args [0] = src;
3372
3373                         /* klass */
3374                         args [1] = klass_inst;
3375
3376                         return mono_emit_jit_icall (cfg, mono_object_castclass, args);
3377                 } else {
3378                         /* Simple case, handled by the code below */
3379                 }
3380         }
3381
3382         NEW_BBLOCK (cfg, is_null_bb);
3383
3384         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3385         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, is_null_bb);
3386
3387         save_cast_details (cfg, klass, obj_reg);
3388
3389         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3390                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3391                 mini_emit_iface_cast (cfg, vtable_reg, klass, NULL, NULL);
3392         } else {
3393                 int klass_reg = alloc_preg (cfg);
3394
3395                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3396
3397                 if (!klass->rank && !cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
3398                         /* the remoting code is broken, access the class for now */
3399                         if (0) { /*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
3400                                 MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
3401                                 if (!vt) {
3402                                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3403                                         cfg->exception_ptr = klass;
3404                                         return NULL;
3405                                 }
3406                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
3407                         } else {
3408                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3409                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
3410                         }
3411                         MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
3412                 } else {
3413                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3414                         mini_emit_castclass_inst (cfg, obj_reg, klass_reg, klass, klass_inst, is_null_bb);
3415                 }
3416         }
3417
3418         MONO_START_BB (cfg, is_null_bb);
3419
3420         reset_cast_details (cfg);
3421
3422         return src;
3423 }
3424
3425 /*
3426  * Returns NULL and set the cfg exception on error.
3427  */
3428 static MonoInst*
3429 handle_isinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src, int context_used)
3430 {
3431         MonoInst *ins;
3432         MonoBasicBlock *is_null_bb, *false_bb, *end_bb;
3433         int obj_reg = src->dreg;
3434         int vtable_reg = alloc_preg (cfg);
3435         int res_reg = alloc_preg (cfg);
3436         MonoInst *klass_inst = NULL;
3437
3438         if (context_used) {
3439                 MonoInst *args [3];
3440
3441                 if(mini_class_has_reference_variant_generic_argument (klass, context_used)) {
3442                         MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
3443                         MonoInst *cache_ins;
3444
3445                         cache_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_CAST_CACHE);
3446
3447                         /* obj */
3448                         args [0] = src;
3449
3450                         /* klass - it's the second element of the cache entry*/
3451                         EMIT_NEW_LOAD_MEMBASE (cfg, args [1], OP_LOAD_MEMBASE, alloc_preg (cfg), cache_ins->dreg, sizeof (gpointer));
3452
3453                         /* cache */
3454                         args [2] = cache_ins;
3455
3456                         return mono_emit_method_call (cfg, mono_isinst, args, NULL);
3457                 }
3458
3459                 klass_inst = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
3460
3461                 if (is_complex_isinst (klass)) {
3462                         /* Complex case, handle by an icall */
3463
3464                         /* obj */
3465                         args [0] = src;
3466
3467                         /* klass */
3468                         args [1] = klass_inst;
3469
3470                         return mono_emit_jit_icall (cfg, mono_object_isinst, args);
3471                 } else {
3472                         /* Simple case, the code below can handle it */
3473                 }
3474         }
3475
3476         NEW_BBLOCK (cfg, is_null_bb);
3477         NEW_BBLOCK (cfg, false_bb);
3478         NEW_BBLOCK (cfg, end_bb);
3479
3480         /* Do the assignment at the beginning, so the other assignment can be if converted */
3481         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, res_reg, obj_reg);
3482         ins->type = STACK_OBJ;
3483         ins->klass = klass;
3484
3485         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3486         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, is_null_bb);
3487
3488         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, vtable_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3489
3490         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3491                 g_assert (!context_used);
3492                 /* the is_null_bb target simply copies the input register to the output */
3493                 mini_emit_iface_cast (cfg, vtable_reg, klass, false_bb, is_null_bb);
3494         } else {
3495                 int klass_reg = alloc_preg (cfg);
3496
3497                 if (klass->rank) {
3498                         int rank_reg = alloc_preg (cfg);
3499                         int eclass_reg = alloc_preg (cfg);
3500
3501                         g_assert (!context_used);
3502                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, rank_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
3503                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, rank_reg, klass->rank);
3504                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
3505                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3506                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, eclass_reg, klass_reg, G_STRUCT_OFFSET (MonoClass, cast_class));
3507                         if (klass->cast_class == mono_defaults.object_class) {
3508                                 int parent_reg = alloc_preg (cfg);
3509                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, parent_reg, eclass_reg, G_STRUCT_OFFSET (MonoClass, parent));
3510                                 mini_emit_class_check_branch (cfg, parent_reg, mono_defaults.enum_class->parent, OP_PBNE_UN, is_null_bb);
3511                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
3512                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
3513                         } else if (klass->cast_class == mono_defaults.enum_class->parent) {
3514                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class->parent, OP_PBEQ, is_null_bb);
3515                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);                          
3516                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
3517                         } else if (klass->cast_class == mono_defaults.enum_class) {
3518                                 mini_emit_class_check_branch (cfg, eclass_reg, mono_defaults.enum_class, OP_PBEQ, is_null_bb);
3519                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false_bb);
3520                         } else if (klass->cast_class->flags & TYPE_ATTRIBUTE_INTERFACE) {
3521                                 mini_emit_iface_class_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
3522                         } else {
3523                                 if ((klass->rank == 1) && (klass->byval_arg.type == MONO_TYPE_SZARRAY)) {
3524                                         /* Check that the object is a vector too */
3525                                         int bounds_reg = alloc_preg (cfg);
3526                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, obj_reg, G_STRUCT_OFFSET (MonoArray, bounds));
3527                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
3528                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
3529                                 }
3530
3531                                 /* the is_null_bb target simply copies the input register to the output */
3532                                 mini_emit_isninst_cast (cfg, eclass_reg, klass->cast_class, false_bb, is_null_bb);
3533                         }
3534                 } else if (mono_class_is_nullable (klass)) {
3535                         g_assert (!context_used);
3536                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3537                         /* the is_null_bb target simply copies the input register to the output */
3538                         mini_emit_isninst_cast (cfg, klass_reg, klass->cast_class, false_bb, is_null_bb);
3539                 } else {
3540                         if (!cfg->compile_aot && !(cfg->opt & MONO_OPT_SHARED) && (klass->flags & TYPE_ATTRIBUTE_SEALED)) {
3541                                 g_assert (!context_used);
3542                                 /* the remoting code is broken, access the class for now */
3543                                 if (0) {/*FIXME what exactly is broken? This change refers to r39380 from 2005 and mention some remoting fixes were due.*/
3544                                         MonoVTable *vt = mono_class_vtable (cfg->domain, klass);
3545                                         if (!vt) {
3546                                                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
3547                                                 cfg->exception_ptr = klass;
3548                                                 return NULL;
3549                                         }
3550                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, vtable_reg, vt);
3551                                 } else {
3552                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3553                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, klass_reg, klass);
3554                                 }
3555                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false_bb);
3556                                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, is_null_bb);
3557                         } else {
3558                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, vtable_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3559                                 /* the is_null_bb target simply copies the input register to the output */
3560                                 mini_emit_isninst_cast_inst (cfg, klass_reg, klass, klass_inst, false_bb, is_null_bb);
3561                         }
3562                 }
3563         }
3564
3565         MONO_START_BB (cfg, false_bb);
3566
3567         MONO_EMIT_NEW_PCONST (cfg, res_reg, 0);
3568         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3569
3570         MONO_START_BB (cfg, is_null_bb);
3571
3572         MONO_START_BB (cfg, end_bb);
3573
3574         return ins;
3575 }
3576
3577 static MonoInst*
3578 handle_cisinst (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
3579 {
3580         /* This opcode takes as input an object reference and a class, and returns:
3581         0) if the object is an instance of the class,
3582         1) if the object is not instance of the class,
3583         2) if the object is a proxy whose type cannot be determined */
3584
3585         MonoInst *ins;
3586         MonoBasicBlock *true_bb, *false_bb, *false2_bb, *end_bb, *no_proxy_bb, *interface_fail_bb;
3587         int obj_reg = src->dreg;
3588         int dreg = alloc_ireg (cfg);
3589         int tmp_reg;
3590         int klass_reg = alloc_preg (cfg);
3591
3592         NEW_BBLOCK (cfg, true_bb);
3593         NEW_BBLOCK (cfg, false_bb);
3594         NEW_BBLOCK (cfg, false2_bb);
3595         NEW_BBLOCK (cfg, end_bb);
3596         NEW_BBLOCK (cfg, no_proxy_bb);
3597
3598         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3599         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, false_bb);
3600
3601         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3602                 NEW_BBLOCK (cfg, interface_fail_bb);
3603
3604                 tmp_reg = alloc_preg (cfg);
3605                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3606                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, true_bb);
3607                 MONO_START_BB (cfg, interface_fail_bb);
3608                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3609                 
3610                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, false_bb);
3611
3612                 tmp_reg = alloc_preg (cfg);
3613                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3614                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3615                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBNE_UN, false2_bb);                
3616         } else {
3617                 tmp_reg = alloc_preg (cfg);
3618                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3619                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3620
3621                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
3622                 tmp_reg = alloc_preg (cfg);
3623                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
3624                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
3625
3626                 tmp_reg = alloc_preg (cfg);             
3627                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3628                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3629                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
3630                 
3631                 mini_emit_isninst_cast (cfg, klass_reg, klass, false2_bb, true_bb);
3632                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, false2_bb);
3633
3634                 MONO_START_BB (cfg, no_proxy_bb);
3635
3636                 mini_emit_isninst_cast (cfg, klass_reg, klass, false_bb, true_bb);
3637         }
3638
3639         MONO_START_BB (cfg, false_bb);
3640
3641         MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3642         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3643
3644         MONO_START_BB (cfg, false2_bb);
3645
3646         MONO_EMIT_NEW_ICONST (cfg, dreg, 2);
3647         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3648
3649         MONO_START_BB (cfg, true_bb);
3650
3651         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
3652
3653         MONO_START_BB (cfg, end_bb);
3654
3655         /* FIXME: */
3656         MONO_INST_NEW (cfg, ins, OP_ICONST);
3657         ins->dreg = dreg;
3658         ins->type = STACK_I4;
3659
3660         return ins;
3661 }
3662
3663 static MonoInst*
3664 handle_ccastclass (MonoCompile *cfg, MonoClass *klass, MonoInst *src)
3665 {
3666         /* This opcode takes as input an object reference and a class, and returns:
3667         0) if the object is an instance of the class,
3668         1) if the object is a proxy whose type cannot be determined
3669         an InvalidCastException exception is thrown otherwhise*/
3670         
3671         MonoInst *ins;
3672         MonoBasicBlock *end_bb, *ok_result_bb, *no_proxy_bb, *interface_fail_bb, *fail_1_bb;
3673         int obj_reg = src->dreg;
3674         int dreg = alloc_ireg (cfg);
3675         int tmp_reg = alloc_preg (cfg);
3676         int klass_reg = alloc_preg (cfg);
3677
3678         NEW_BBLOCK (cfg, end_bb);
3679         NEW_BBLOCK (cfg, ok_result_bb);
3680
3681         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, obj_reg, 0);
3682         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, ok_result_bb);
3683
3684         save_cast_details (cfg, klass, obj_reg);
3685
3686         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3687                 NEW_BBLOCK (cfg, interface_fail_bb);
3688         
3689                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3690                 mini_emit_iface_cast (cfg, tmp_reg, klass, interface_fail_bb, ok_result_bb);
3691                 MONO_START_BB (cfg, interface_fail_bb);
3692                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3693
3694                 mini_emit_class_check (cfg, klass_reg, mono_defaults.transparent_proxy_class);
3695
3696                 tmp_reg = alloc_preg (cfg);             
3697                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3698                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3699                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "InvalidCastException");
3700                 
3701                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3702                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3703                 
3704         } else {
3705                 NEW_BBLOCK (cfg, no_proxy_bb);
3706
3707                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoObject, vtable));
3708                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoVTable, klass));
3709                 mini_emit_class_check_branch (cfg, klass_reg, mono_defaults.transparent_proxy_class, OP_PBNE_UN, no_proxy_bb);          
3710
3711                 tmp_reg = alloc_preg (cfg);
3712                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, remote_class));
3713                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, tmp_reg, G_STRUCT_OFFSET (MonoRemoteClass, proxy_class));
3714
3715                 tmp_reg = alloc_preg (cfg);
3716                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, tmp_reg, obj_reg, G_STRUCT_OFFSET (MonoTransparentProxy, custom_type_info));
3717                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, tmp_reg, 0);
3718                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, no_proxy_bb);
3719
3720                 NEW_BBLOCK (cfg, fail_1_bb);
3721                 
3722                 mini_emit_isninst_cast (cfg, klass_reg, klass, fail_1_bb, ok_result_bb);
3723
3724                 MONO_START_BB (cfg, fail_1_bb);
3725
3726                 MONO_EMIT_NEW_ICONST (cfg, dreg, 1);
3727                 MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
3728
3729                 MONO_START_BB (cfg, no_proxy_bb);
3730
3731                 mini_emit_castclass (cfg, obj_reg, klass_reg, klass, ok_result_bb);
3732         }
3733
3734         MONO_START_BB (cfg, ok_result_bb);
3735
3736         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
3737
3738         MONO_START_BB (cfg, end_bb);
3739
3740         /* FIXME: */
3741         MONO_INST_NEW (cfg, ins, OP_ICONST);
3742         ins->dreg = dreg;
3743         ins->type = STACK_I4;
3744
3745         return ins;
3746 }
3747
3748 /*
3749  * Returns NULL and set the cfg exception on error.
3750  */
3751 static G_GNUC_UNUSED MonoInst*
3752 handle_delegate_ctor (MonoCompile *cfg, MonoClass *klass, MonoInst *target, MonoMethod *method, int context_used)
3753 {
3754         MonoInst *ptr;
3755         int dreg;
3756         gpointer *trampoline;
3757         MonoInst *obj, *method_ins, *tramp_ins;
3758         MonoDomain *domain;
3759         guint8 **code_slot;
3760
3761         obj = handle_alloc (cfg, klass, FALSE, 0);
3762         if (!obj)
3763                 return NULL;
3764
3765         /* Inline the contents of mono_delegate_ctor */
3766
3767         /* Set target field */
3768         /* Optimize away setting of NULL target */
3769         if (!(target->opcode == OP_PCONST && target->inst_p0 == 0)) {
3770                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target), target->dreg);
3771                 if (cfg->gen_write_barriers) {
3772                         dreg = alloc_preg (cfg);
3773                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, target));
3774                         emit_write_barrier (cfg, ptr, target, 0);
3775                 }
3776         }
3777
3778         /* Set method field */
3779         method_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD);
3780         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method), method_ins->dreg);
3781         if (cfg->gen_write_barriers) {
3782                 dreg = alloc_preg (cfg);
3783                 EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method));
3784                 emit_write_barrier (cfg, ptr, method_ins, 0);
3785         }
3786         /* 
3787          * To avoid looking up the compiled code belonging to the target method
3788          * in mono_delegate_trampoline (), we allocate a per-domain memory slot to
3789          * store it, and we fill it after the method has been compiled.
3790          */
3791         if (!cfg->compile_aot && !method->dynamic) {
3792                 MonoInst *code_slot_ins;
3793
3794                 if (context_used) {
3795                         code_slot_ins = emit_get_rgctx_method (cfg, context_used, method, MONO_RGCTX_INFO_METHOD_DELEGATE_CODE);
3796                 } else {
3797                         domain = mono_domain_get ();
3798                         mono_domain_lock (domain);
3799                         if (!domain_jit_info (domain)->method_code_hash)
3800                                 domain_jit_info (domain)->method_code_hash = g_hash_table_new (NULL, NULL);
3801                         code_slot = g_hash_table_lookup (domain_jit_info (domain)->method_code_hash, method);
3802                         if (!code_slot) {
3803                                 code_slot = mono_domain_alloc0 (domain, sizeof (gpointer));
3804                                 g_hash_table_insert (domain_jit_info (domain)->method_code_hash, method, code_slot);
3805                         }
3806                         mono_domain_unlock (domain);
3807
3808                         EMIT_NEW_PCONST (cfg, code_slot_ins, code_slot);
3809                 }
3810                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, method_code), code_slot_ins->dreg);           
3811         }
3812
3813         /* Set invoke_impl field */
3814         if (cfg->compile_aot) {
3815                 EMIT_NEW_AOTCONST (cfg, tramp_ins, MONO_PATCH_INFO_DELEGATE_TRAMPOLINE, klass);
3816         } else {
3817                 trampoline = mono_create_delegate_trampoline (klass);
3818                 EMIT_NEW_PCONST (cfg, tramp_ins, trampoline);
3819         }
3820         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, obj->dreg, G_STRUCT_OFFSET (MonoDelegate, invoke_impl), tramp_ins->dreg);
3821
3822         /* All the checks which are in mono_delegate_ctor () are done by the delegate trampoline */
3823
3824         return obj;
3825 }
3826
3827 static MonoInst*
3828 handle_array_new (MonoCompile *cfg, int rank, MonoInst **sp, unsigned char *ip)
3829 {
3830         MonoJitICallInfo *info;
3831
3832         /* Need to register the icall so it gets an icall wrapper */
3833         info = mono_get_array_new_va_icall (rank);
3834
3835         cfg->flags |= MONO_CFG_HAS_VARARGS;
3836
3837         /* mono_array_new_va () needs a vararg calling convention */
3838         cfg->disable_llvm = TRUE;
3839
3840         /* FIXME: This uses info->sig, but it should use the signature of the wrapper */
3841         return mono_emit_native_call (cfg, mono_icall_get_wrapper (info), info->sig, sp);
3842 }
3843
3844 static void
3845 mono_emit_load_got_addr (MonoCompile *cfg)
3846 {
3847         MonoInst *getaddr, *dummy_use;
3848
3849         if (!cfg->got_var || cfg->got_var_allocated)
3850                 return;
3851
3852         MONO_INST_NEW (cfg, getaddr, OP_LOAD_GOTADDR);
3853         getaddr->dreg = cfg->got_var->dreg;
3854
3855         /* Add it to the start of the first bblock */
3856         if (cfg->bb_entry->code) {
3857                 getaddr->next = cfg->bb_entry->code;
3858                 cfg->bb_entry->code = getaddr;
3859         }
3860         else
3861                 MONO_ADD_INS (cfg->bb_entry, getaddr);
3862
3863         cfg->got_var_allocated = TRUE;
3864
3865         /* 
3866          * Add a dummy use to keep the got_var alive, since real uses might
3867          * only be generated by the back ends.
3868          * Add it to end_bblock, so the variable's lifetime covers the whole
3869          * method.
3870          * It would be better to make the usage of the got var explicit in all
3871          * cases when the backend needs it (i.e. calls, throw etc.), so this
3872          * wouldn't be needed.
3873          */
3874         NEW_DUMMY_USE (cfg, dummy_use, cfg->got_var);
3875         MONO_ADD_INS (cfg->bb_exit, dummy_use);
3876 }
3877
3878 static int inline_limit;
3879 static gboolean inline_limit_inited;
3880
3881 static gboolean
3882 mono_method_check_inlining (MonoCompile *cfg, MonoMethod *method)
3883 {
3884         MonoMethodHeaderSummary header;
3885         MonoVTable *vtable;
3886 #ifdef MONO_ARCH_SOFT_FLOAT
3887         MonoMethodSignature *sig = mono_method_signature (method);
3888         int i;
3889 #endif
3890
3891         if (cfg->generic_sharing_context)
3892                 return FALSE;
3893
3894         if (cfg->inline_depth > 10)
3895                 return FALSE;
3896
3897 #ifdef MONO_ARCH_HAVE_LMF_OPS
3898         if (((method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
3899                  (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) &&
3900             !MONO_TYPE_ISSTRUCT (signature->ret) && !mini_class_is_system_array (method->klass))
3901                 return TRUE;
3902 #endif
3903
3904
3905         if (!mono_method_get_header_summary (method, &header))
3906                 return FALSE;
3907
3908         /*runtime, icall and pinvoke are checked by summary call*/
3909         if ((method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING) ||
3910             (method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED) ||
3911             (method->klass->marshalbyref) ||
3912             header.has_clauses)
3913                 return FALSE;
3914
3915         /* also consider num_locals? */
3916         /* Do the size check early to avoid creating vtables */
3917         if (!inline_limit_inited) {
3918                 if (getenv ("MONO_INLINELIMIT"))
3919                         inline_limit = atoi (getenv ("MONO_INLINELIMIT"));
3920                 else
3921                         inline_limit = INLINE_LENGTH_LIMIT;
3922                 inline_limit_inited = TRUE;
3923         }
3924         if (header.code_size >= inline_limit)
3925                 return FALSE;
3926
3927         /*
3928          * if we can initialize the class of the method right away, we do,
3929          * otherwise we don't allow inlining if the class needs initialization,
3930          * since it would mean inserting a call to mono_runtime_class_init()
3931          * inside the inlined code
3932          */
3933         if (!(cfg->opt & MONO_OPT_SHARED)) {
3934                 if (method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT) {
3935                         if (cfg->run_cctors && method->klass->has_cctor) {
3936                                 /*FIXME it would easier and lazier to just use mono_class_try_get_vtable */
3937                                 if (!method->klass->runtime_info)
3938                                         /* No vtable created yet */
3939                                         return FALSE;
3940                                 vtable = mono_class_vtable (cfg->domain, method->klass);
3941                                 if (!vtable)
3942                                         return FALSE;
3943                                 /* This makes so that inline cannot trigger */
3944                                 /* .cctors: too many apps depend on them */
3945                                 /* running with a specific order... */
3946                                 if (! vtable->initialized)
3947                                         return FALSE;
3948                                 mono_runtime_class_init (vtable);
3949                         }
3950                 } else if (mono_class_needs_cctor_run (method->klass, NULL)) {
3951                         if (!method->klass->runtime_info)
3952                                 /* No vtable created yet */
3953                                 return FALSE;
3954                         vtable = mono_class_vtable (cfg->domain, method->klass);
3955                         if (!vtable)
3956                                 return FALSE;
3957                         if (!vtable->initialized)
3958                                 return FALSE;
3959                 }
3960         } else {
3961                 /* 
3962                  * If we're compiling for shared code
3963                  * the cctor will need to be run at aot method load time, for example,
3964                  * or at the end of the compilation of the inlining method.
3965                  */
3966                 if (mono_class_needs_cctor_run (method->klass, NULL) && !((method->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)))
3967                         return FALSE;
3968         }
3969
3970         /*
3971          * CAS - do not inline methods with declarative security
3972          * Note: this has to be before any possible return TRUE;
3973          */
3974         if (mono_method_has_declsec (method))
3975                 return FALSE;
3976
3977 #ifdef MONO_ARCH_SOFT_FLOAT
3978         /* FIXME: */
3979         if (sig->ret && sig->ret->type == MONO_TYPE_R4)
3980                 return FALSE;
3981         for (i = 0; i < sig->param_count; ++i)
3982                 if (!sig->params [i]->byref && sig->params [i]->type == MONO_TYPE_R4)
3983                         return FALSE;
3984 #endif
3985
3986         return TRUE;
3987 }
3988
3989 static gboolean
3990 mini_field_access_needs_cctor_run (MonoCompile *cfg, MonoMethod *method, MonoVTable *vtable)
3991 {
3992         if (vtable->initialized && !cfg->compile_aot)
3993                 return FALSE;
3994
3995         if (vtable->klass->flags & TYPE_ATTRIBUTE_BEFORE_FIELD_INIT)
3996                 return FALSE;
3997
3998         if (!mono_class_needs_cctor_run (vtable->klass, method))
3999                 return FALSE;
4000
4001         if (! (method->flags & METHOD_ATTRIBUTE_STATIC) && (vtable->klass == method->klass))
4002                 /* The initialization is already done before the method is called */
4003                 return FALSE;
4004
4005         return TRUE;
4006 }
4007
4008 static MonoInst*
4009 mini_emit_ldelema_1_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index, gboolean bcheck)
4010 {
4011         MonoInst *ins;
4012         guint32 size;
4013         int mult_reg, add_reg, array_reg, index_reg, index2_reg;
4014
4015         mono_class_init (klass);
4016         size = mono_class_array_element_size (klass);
4017
4018         mult_reg = alloc_preg (cfg);
4019         array_reg = arr->dreg;
4020         index_reg = index->dreg;
4021
4022 #if SIZEOF_REGISTER == 8
4023         /* The array reg is 64 bits but the index reg is only 32 */
4024         if (COMPILE_LLVM (cfg)) {
4025                 /* Not needed */
4026                 index2_reg = index_reg;
4027         } else {
4028                 index2_reg = alloc_preg (cfg);
4029                 MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index2_reg, index_reg);
4030         }
4031 #else
4032         if (index->type == STACK_I8) {
4033                 index2_reg = alloc_preg (cfg);
4034                 MONO_EMIT_NEW_UNALU (cfg, OP_LCONV_TO_I4, index2_reg, index_reg);
4035         } else {
4036                 index2_reg = index_reg;
4037         }
4038 #endif
4039
4040         if (bcheck)
4041                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index2_reg);
4042
4043 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4044         if (size == 1 || size == 2 || size == 4 || size == 8) {
4045                 static const int fast_log2 [] = { 1, 0, 1, -1, 2, -1, -1, -1, 3 };
4046
4047                 EMIT_NEW_X86_LEA (cfg, ins, array_reg, index2_reg, fast_log2 [size], G_STRUCT_OFFSET (MonoArray, vector));
4048                 ins->type = STACK_PTR;
4049
4050                 return ins;
4051         }
4052 #endif          
4053
4054         add_reg = alloc_preg (cfg);
4055
4056         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_MUL_IMM, mult_reg, index2_reg, size);
4057         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, array_reg, mult_reg);
4058         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4059         ins->type = STACK_PTR;
4060         MONO_ADD_INS (cfg->cbb, ins);
4061
4062         return ins;
4063 }
4064
4065 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4066 static MonoInst*
4067 mini_emit_ldelema_2_ins (MonoCompile *cfg, MonoClass *klass, MonoInst *arr, MonoInst *index_ins1, MonoInst *index_ins2)
4068 {
4069         int bounds_reg = alloc_preg (cfg);
4070         int add_reg = alloc_preg (cfg);
4071         int mult_reg = alloc_preg (cfg);
4072         int mult2_reg = alloc_preg (cfg);
4073         int low1_reg = alloc_preg (cfg);
4074         int low2_reg = alloc_preg (cfg);
4075         int high1_reg = alloc_preg (cfg);
4076         int high2_reg = alloc_preg (cfg);
4077         int realidx1_reg = alloc_preg (cfg);
4078         int realidx2_reg = alloc_preg (cfg);
4079         int sum_reg = alloc_preg (cfg);
4080         int index1, index2;
4081         MonoInst *ins;
4082         guint32 size;
4083
4084         mono_class_init (klass);
4085         size = mono_class_array_element_size (klass);
4086
4087         index1 = index_ins1->dreg;
4088         index2 = index_ins2->dreg;
4089
4090         /* range checking */
4091         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, bounds_reg, 
4092                                        arr->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4093
4094         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low1_reg, 
4095                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4096         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx1_reg, index1, low1_reg);
4097         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high1_reg, 
4098                                        bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4099         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high1_reg, realidx1_reg);
4100         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4101
4102         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, low2_reg, 
4103                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4104         MONO_EMIT_NEW_BIALU (cfg, OP_PSUB, realidx2_reg, index2, low2_reg);
4105         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADI4_MEMBASE, high2_reg, 
4106                                        bounds_reg, sizeof (MonoArrayBounds) + G_STRUCT_OFFSET (MonoArrayBounds, length));
4107         MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, high2_reg, realidx2_reg);
4108         MONO_EMIT_NEW_COND_EXC (cfg, LE_UN, "IndexOutOfRangeException");
4109
4110         MONO_EMIT_NEW_BIALU (cfg, OP_PMUL, mult_reg, high2_reg, realidx1_reg);
4111         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, mult_reg, realidx2_reg);
4112         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_PMUL_IMM, mult2_reg, sum_reg, size);
4113         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult2_reg, arr->dreg);
4114         NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, add_reg, add_reg, G_STRUCT_OFFSET (MonoArray, vector));
4115
4116         ins->type = STACK_MP;
4117         ins->klass = klass;
4118         MONO_ADD_INS (cfg->cbb, ins);
4119
4120         return ins;
4121 }
4122 #endif
4123
4124 static MonoInst*
4125 mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, unsigned char *ip, gboolean is_set)
4126 {
4127         int rank;
4128         MonoInst *addr;
4129         MonoMethod *addr_method;
4130         int element_size;
4131
4132         rank = mono_method_signature (cmethod)->param_count - (is_set? 1: 0);
4133
4134         if (rank == 1)
4135                 return mini_emit_ldelema_1_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], TRUE);
4136
4137 #ifndef MONO_ARCH_EMULATE_MUL_DIV
4138         /* emit_ldelema_2 depends on OP_LMUL */
4139         if (rank == 2 && (cfg->opt & MONO_OPT_INTRINS)) {
4140                 return mini_emit_ldelema_2_ins (cfg, cmethod->klass->element_class, sp [0], sp [1], sp [2]);
4141         }
4142 #endif
4143
4144         element_size = mono_class_array_element_size (cmethod->klass->element_class);
4145         addr_method = mono_marshal_get_array_address (rank, element_size);
4146         addr = mono_emit_method_call (cfg, addr_method, sp, NULL);
4147
4148         return addr;
4149 }
4150
4151 static MonoBreakPolicy
4152 always_insert_breakpoint (MonoMethod *method)
4153 {
4154         return MONO_BREAK_POLICY_ALWAYS;
4155 }
4156
4157 static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
4158
4159 /**
4160  * mono_set_break_policy:
4161  * policy_callback: the new callback function
4162  *
4163  * Allow embedders to decide wherther to actually obey breakpoint instructions
4164  * (both break IL instructions and Debugger.Break () method calls), for example
4165  * to not allow an app to be aborted by a perfectly valid IL opcode when executing
4166  * untrusted or semi-trusted code.
4167  *
4168  * @policy_callback will be called every time a break point instruction needs to
4169  * be inserted with the method argument being the method that calls Debugger.Break()
4170  * or has the IL break instruction. The callback should return #MONO_BREAK_POLICY_NEVER
4171  * if it wants the breakpoint to not be effective in the given method.
4172  * #MONO_BREAK_POLICY_ALWAYS is the default.
4173  */
4174 void
4175 mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
4176 {
4177         if (policy_callback)
4178                 break_policy_func = policy_callback;
4179         else
4180                 break_policy_func = always_insert_breakpoint;
4181 }
4182
4183 static gboolean
4184 should_insert_brekpoint (MonoMethod *method) {
4185         switch (break_policy_func (method)) {
4186         case MONO_BREAK_POLICY_ALWAYS:
4187                 return TRUE;
4188         case MONO_BREAK_POLICY_NEVER:
4189                 return FALSE;
4190         case MONO_BREAK_POLICY_ON_DBG:
4191                 return mono_debug_using_mono_debugger ();
4192         default:
4193                 g_warning ("Incorrect value returned from break policy callback");
4194                 return FALSE;
4195         }
4196 }
4197
4198 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
4199 static MonoInst*
4200 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
4201 {
4202         MonoInst *addr, *store, *load;
4203         MonoClass *eklass = mono_class_from_mono_type (fsig->params [2]);
4204
4205         /* the bounds check is already done by the callers */
4206         addr = mini_emit_ldelema_1_ins (cfg, eklass, args [0], args [1], FALSE);
4207         if (is_set) {
4208                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, args [2]->dreg, 0);
4209                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, addr->dreg, 0, load->dreg);
4210         } else {
4211                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, &eklass->byval_arg, addr->dreg, 0);
4212                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, &eklass->byval_arg, args [2]->dreg, 0, load->dreg);
4213         }
4214         return store;
4215 }
4216
4217 static MonoInst*
4218 mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4219 {
4220         MonoInst *ins = NULL;
4221 #ifdef MONO_ARCH_SIMD_INTRINSICS
4222         if (cfg->opt & MONO_OPT_SIMD) {
4223                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
4224                 if (ins)
4225                         return ins;
4226         }
4227 #endif
4228
4229         return ins;
4230 }
4231
4232 static MonoInst*
4233 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
4234 {
4235         MonoInst *ins = NULL;
4236         
4237         static MonoClass *runtime_helpers_class = NULL;
4238         if (! runtime_helpers_class)
4239                 runtime_helpers_class = mono_class_from_name (mono_defaults.corlib,
4240                         "System.Runtime.CompilerServices", "RuntimeHelpers");
4241
4242         if (cmethod->klass == mono_defaults.string_class) {
4243                 if (strcmp (cmethod->name, "get_Chars") == 0) {
4244                         int dreg = alloc_ireg (cfg);
4245                         int index_reg = alloc_preg (cfg);
4246                         int mult_reg = alloc_preg (cfg);
4247                         int add_reg = alloc_preg (cfg);
4248
4249 #if SIZEOF_REGISTER == 8
4250                         /* The array reg is 64 bits but the index reg is only 32 */
4251                         MONO_EMIT_NEW_UNALU (cfg, OP_SEXT_I4, index_reg, args [1]->dreg);
4252 #else
4253                         index_reg = args [1]->dreg;
4254 #endif  
4255                         MONO_EMIT_BOUNDS_CHECK (cfg, args [0]->dreg, MonoString, length, index_reg);
4256
4257 #if defined(TARGET_X86) || defined(TARGET_AMD64)
4258                         EMIT_NEW_X86_LEA (cfg, ins, args [0]->dreg, index_reg, 1, G_STRUCT_OFFSET (MonoString, chars));
4259                         add_reg = ins->dreg;
4260                         /* Avoid a warning */
4261                         mult_reg = 0;
4262                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
4263                                                                    add_reg, 0);
4264 #else
4265                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, index_reg, 1);
4266                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
4267                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU2_MEMBASE, dreg, 
4268                                                                    add_reg, G_STRUCT_OFFSET (MonoString, chars));
4269 #endif
4270                         type_from_op (ins, NULL, NULL);
4271                         return ins;
4272                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4273                         int dreg = alloc_ireg (cfg);
4274                         /* Decompose later to allow more optimizations */
4275                         EMIT_NEW_UNALU (cfg, ins, OP_STRLEN, dreg, args [0]->dreg);
4276                         ins->type = STACK_I4;
4277                         ins->flags |= MONO_INST_FAULT;
4278                         cfg->cbb->has_array_access = TRUE;
4279                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
4280
4281                         return ins;
4282                 } else if (strcmp (cmethod->name, "InternalSetChar") == 0) {
4283                         int mult_reg = alloc_preg (cfg);
4284                         int add_reg = alloc_preg (cfg);
4285
4286                         /* The corlib functions check for oob already. */
4287                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, mult_reg, args [1]->dreg, 1);
4288                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, add_reg, mult_reg, args [0]->dreg);
4289                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI2_MEMBASE_REG, add_reg, G_STRUCT_OFFSET (MonoString, chars), args [2]->dreg);
4290                         return cfg->cbb->last_ins;
4291                 } else 
4292                         return NULL;
4293         } else if (cmethod->klass == mono_defaults.object_class) {
4294
4295                 if (strcmp (cmethod->name, "GetType") == 0) {
4296                         int dreg = alloc_preg (cfg);
4297                         int vt_reg = alloc_preg (cfg);
4298                         MONO_EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, vt_reg, args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
4299                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, vt_reg, G_STRUCT_OFFSET (MonoVTable, type));
4300                         type_from_op (ins, NULL, NULL);
4301
4302                         return ins;
4303 #if !defined(MONO_ARCH_EMULATE_MUL_DIV)
4304                 } else if (strcmp (cmethod->name, "InternalGetHashCode") == 0 && !mono_gc_is_moving ()) {
4305                         int dreg = alloc_ireg (cfg);
4306                         int t1 = alloc_ireg (cfg);
4307         
4308                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, t1, args [0]->dreg, 3);
4309                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_MUL_IMM, dreg, t1, 2654435761u);
4310                         ins->type = STACK_I4;
4311
4312                         return ins;
4313 #endif
4314                 } else if (strcmp (cmethod->name, ".ctor") == 0) {
4315                         MONO_INST_NEW (cfg, ins, OP_NOP);
4316                         MONO_ADD_INS (cfg->cbb, ins);
4317                         return ins;
4318                 } else
4319                         return NULL;
4320         } else if (cmethod->klass == mono_defaults.array_class) {
4321                 if (strcmp (cmethod->name + 1, "etGenericValueImpl") == 0)
4322                         return emit_array_generic_access (cfg, fsig, args, *cmethod->name == 'S');
4323
4324 #ifndef MONO_BIG_ARRAYS
4325                 /*
4326                  * This is an inline version of GetLength/GetLowerBound(0) used frequently in
4327                  * Array methods.
4328                  */
4329                 if ((strcmp (cmethod->name, "GetLength") == 0 || strcmp (cmethod->name, "GetLowerBound") == 0) && args [1]->opcode == OP_ICONST && args [1]->inst_c0 == 0) {
4330                         int dreg = alloc_ireg (cfg);
4331                         int bounds_reg = alloc_ireg (cfg);
4332                         MonoBasicBlock *end_bb, *szarray_bb;
4333                         gboolean get_length = strcmp (cmethod->name, "GetLength") == 0;
4334
4335                         NEW_BBLOCK (cfg, end_bb);
4336                         NEW_BBLOCK (cfg, szarray_bb);
4337
4338                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOAD_MEMBASE, bounds_reg,
4339                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, bounds));
4340                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, bounds_reg, 0);
4341                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBEQ, szarray_bb);
4342                         /* Non-szarray case */
4343                         if (get_length)
4344                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
4345                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, length));
4346                         else
4347                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
4348                                                                            bounds_reg, G_STRUCT_OFFSET (MonoArrayBounds, lower_bound));
4349                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_BR, end_bb);
4350                         MONO_START_BB (cfg, szarray_bb);
4351                         /* Szarray case */
4352                         if (get_length)
4353                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, dreg,
4354                                                                            args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
4355                         else
4356                                 MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
4357                         MONO_START_BB (cfg, end_bb);
4358
4359                         EMIT_NEW_UNALU (cfg, ins, OP_MOVE, dreg, dreg);
4360                         ins->type = STACK_I4;
4361                         
4362                         return ins;
4363                 }
4364 #endif
4365
4366                 if (cmethod->name [0] != 'g')
4367                         return NULL;
4368
4369                 if (strcmp (cmethod->name, "get_Rank") == 0) {
4370                         int dreg = alloc_ireg (cfg);
4371                         int vtable_reg = alloc_preg (cfg);
4372                         MONO_EMIT_NEW_LOAD_MEMBASE_OP_FAULT (cfg, OP_LOAD_MEMBASE, vtable_reg, 
4373                                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoObject, vtable));
4374                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADU1_MEMBASE, dreg,
4375                                                                    vtable_reg, G_STRUCT_OFFSET (MonoVTable, rank));
4376                         type_from_op (ins, NULL, NULL);
4377
4378                         return ins;
4379                 } else if (strcmp (cmethod->name, "get_Length") == 0) {
4380                         int dreg = alloc_ireg (cfg);
4381
4382                         EMIT_NEW_LOAD_MEMBASE_FAULT (cfg, ins, OP_LOADI4_MEMBASE, dreg, 
4383                                                                                  args [0]->dreg, G_STRUCT_OFFSET (MonoArray, max_length));
4384                         type_from_op (ins, NULL, NULL);
4385
4386                         return ins;
4387                 } else
4388                         return NULL;
4389         } else if (cmethod->klass == runtime_helpers_class) {
4390
4391                 if (strcmp (cmethod->name, "get_OffsetToStringData") == 0) {
4392                         EMIT_NEW_ICONST (cfg, ins, G_STRUCT_OFFSET (MonoString, chars));
4393                         return ins;
4394                 } else
4395                         return NULL;
4396         } else if (cmethod->klass == mono_defaults.thread_class) {
4397                 if (strcmp (cmethod->name, "SpinWait_nop") == 0) {
4398                         MONO_INST_NEW (cfg, ins, OP_RELAXED_NOP);
4399                         MONO_ADD_INS (cfg->cbb, ins);
4400                         return ins;
4401                 } else if (strcmp (cmethod->name, "MemoryBarrier") == 0) {
4402                         MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
4403                         MONO_ADD_INS (cfg->cbb, ins);
4404                         return ins;
4405                 }
4406         } else if (cmethod->klass == mono_defaults.monitor_class) {
4407 #if defined(MONO_ARCH_MONITOR_OBJECT_REG)
4408                 if (strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) {
4409                         MonoCallInst *call;
4410
4411                         if (COMPILE_LLVM (cfg)) {
4412                                 /* 
4413                                  * Pass the argument normally, the LLVM backend will handle the
4414                                  * calling convention problems.
4415                                  */
4416                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
4417                         } else {
4418                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_ENTER,
4419                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
4420                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
4421                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
4422                         }
4423
4424                         return (MonoInst*)call;
4425                 } else if (strcmp (cmethod->name, "Exit") == 0) {
4426                         MonoCallInst *call;
4427
4428                         if (COMPILE_LLVM (cfg)) {
4429                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT, NULL, helper_sig_monitor_enter_exit_trampoline_llvm, args);
4430                         } else {
4431                                 call = (MonoCallInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_MONITOR_EXIT,
4432                                             NULL, helper_sig_monitor_enter_exit_trampoline, NULL);
4433                                 mono_call_inst_add_outarg_reg (cfg, call, args [0]->dreg,
4434                                                                                            MONO_ARCH_MONITOR_OBJECT_REG, FALSE);
4435                         }
4436
4437                         return (MonoInst*)call;
4438                 }
4439 #elif defined(MONO_ARCH_ENABLE_MONITOR_IL_FASTPATH)
4440                 MonoMethod *fast_method = NULL;
4441
4442                 /* Avoid infinite recursion */
4443                 if (cfg->method->wrapper_type == MONO_WRAPPER_UNKNOWN &&
4444                                 (strcmp (cfg->method->name, "FastMonitorEnter") == 0 ||
4445                                  strcmp (cfg->method->name, "FastMonitorExit") == 0))
4446                         return NULL;
4447
4448                 if ((strcmp (cmethod->name, "Enter") == 0 && fsig->param_count == 1) ||
4449                                 strcmp (cmethod->name, "Exit") == 0)
4450                         fast_method = mono_monitor_get_fast_path (cmethod);
4451                 if (!fast_method)
4452                         return NULL;
4453
4454                 return (MonoInst*)mono_emit_method_call (cfg, fast_method, args, NULL);
4455 #endif
4456         } else if (cmethod->klass->image == mono_defaults.corlib &&
4457                            (strcmp (cmethod->klass->name_space, "System.Threading") == 0) &&
4458                            (strcmp (cmethod->klass->name, "Interlocked") == 0)) {
4459                 ins = NULL;
4460
4461 #if SIZEOF_REGISTER == 8
4462                 if (strcmp (cmethod->name, "Read") == 0 && (fsig->params [0]->type == MONO_TYPE_I8)) {
4463                         /* 64 bit reads are already atomic */
4464                         MONO_INST_NEW (cfg, ins, OP_LOADI8_MEMBASE);
4465                         ins->dreg = mono_alloc_preg (cfg);
4466                         ins->inst_basereg = args [0]->dreg;
4467                         ins->inst_offset = 0;
4468                         MONO_ADD_INS (cfg->cbb, ins);
4469                 }
4470 #endif
4471
4472 #ifdef MONO_ARCH_HAVE_ATOMIC_ADD
4473                 if (strcmp (cmethod->name, "Increment") == 0) {
4474                         MonoInst *ins_iconst;
4475                         guint32 opcode = 0;
4476
4477                         if (fsig->params [0]->type == MONO_TYPE_I4)
4478                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4479 #if SIZEOF_REGISTER == 8
4480                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4481                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4482 #endif
4483                         if (opcode) {
4484                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4485                                 ins_iconst->inst_c0 = 1;
4486                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
4487                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
4488
4489                                 MONO_INST_NEW (cfg, ins, opcode);
4490                                 ins->dreg = mono_alloc_ireg (cfg);
4491                                 ins->inst_basereg = args [0]->dreg;
4492                                 ins->inst_offset = 0;
4493                                 ins->sreg2 = ins_iconst->dreg;
4494                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
4495                                 MONO_ADD_INS (cfg->cbb, ins);
4496                         }
4497                 } else if (strcmp (cmethod->name, "Decrement") == 0) {
4498                         MonoInst *ins_iconst;
4499                         guint32 opcode = 0;
4500
4501                         if (fsig->params [0]->type == MONO_TYPE_I4)
4502                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4503 #if SIZEOF_REGISTER == 8
4504                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4505                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4506 #endif
4507                         if (opcode) {
4508                                 MONO_INST_NEW (cfg, ins_iconst, OP_ICONST);
4509                                 ins_iconst->inst_c0 = -1;
4510                                 ins_iconst->dreg = mono_alloc_ireg (cfg);
4511                                 MONO_ADD_INS (cfg->cbb, ins_iconst);
4512
4513                                 MONO_INST_NEW (cfg, ins, opcode);
4514                                 ins->dreg = mono_alloc_ireg (cfg);
4515                                 ins->inst_basereg = args [0]->dreg;
4516                                 ins->inst_offset = 0;
4517                                 ins->sreg2 = ins_iconst->dreg;
4518                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
4519                                 MONO_ADD_INS (cfg->cbb, ins);
4520                         }
4521                 } else if (strcmp (cmethod->name, "Add") == 0) {
4522                         guint32 opcode = 0;
4523
4524                         if (fsig->params [0]->type == MONO_TYPE_I4)
4525                                 opcode = OP_ATOMIC_ADD_NEW_I4;
4526 #if SIZEOF_REGISTER == 8
4527                         else if (fsig->params [0]->type == MONO_TYPE_I8)
4528                                 opcode = OP_ATOMIC_ADD_NEW_I8;
4529 #endif
4530
4531                         if (opcode) {
4532                                 MONO_INST_NEW (cfg, ins, opcode);
4533                                 ins->dreg = mono_alloc_ireg (cfg);
4534                                 ins->inst_basereg = args [0]->dreg;
4535                                 ins->inst_offset = 0;
4536                                 ins->sreg2 = args [1]->dreg;
4537                                 ins->type = (opcode == OP_ATOMIC_ADD_NEW_I4) ? STACK_I4 : STACK_I8;
4538                                 MONO_ADD_INS (cfg->cbb, ins);
4539                         }
4540                 }
4541 #endif /* MONO_ARCH_HAVE_ATOMIC_ADD */
4542
4543 #ifdef MONO_ARCH_HAVE_ATOMIC_EXCHANGE
4544                 if (strcmp (cmethod->name, "Exchange") == 0) {
4545                         guint32 opcode;
4546                         gboolean is_ref = fsig->params [0]->type == MONO_TYPE_OBJECT;
4547
4548                         if (fsig->params [0]->type == MONO_TYPE_I4)
4549                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4550 #if SIZEOF_REGISTER == 8
4551                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I8) ||
4552                                         (fsig->params [0]->type == MONO_TYPE_I))
4553                                 opcode = OP_ATOMIC_EXCHANGE_I8;
4554 #else
4555                         else if (is_ref || (fsig->params [0]->type == MONO_TYPE_I))
4556                                 opcode = OP_ATOMIC_EXCHANGE_I4;
4557 #endif
4558                         else
4559                                 return NULL;
4560
4561                         MONO_INST_NEW (cfg, ins, opcode);
4562                         ins->dreg = mono_alloc_ireg (cfg);
4563                         ins->inst_basereg = args [0]->dreg;
4564                         ins->inst_offset = 0;
4565                         ins->sreg2 = args [1]->dreg;
4566                         MONO_ADD_INS (cfg->cbb, ins);
4567
4568                         switch (fsig->params [0]->type) {
4569                         case MONO_TYPE_I4:
4570                                 ins->type = STACK_I4;
4571                                 break;
4572                         case MONO_TYPE_I8:
4573                         case MONO_TYPE_I:
4574                                 ins->type = STACK_I8;
4575                                 break;
4576                         case MONO_TYPE_OBJECT:
4577                                 ins->type = STACK_OBJ;
4578                                 break;
4579                         default:
4580                                 g_assert_not_reached ();
4581                         }
4582
4583                         if (cfg->gen_write_barriers && is_ref)
4584                                 emit_write_barrier (cfg, args [0], args [1], -1);
4585                 }
4586 #endif /* MONO_ARCH_HAVE_ATOMIC_EXCHANGE */
4587  
4588 #ifdef MONO_ARCH_HAVE_ATOMIC_CAS
4589                 if ((strcmp (cmethod->name, "CompareExchange") == 0)) {
4590                         int size = 0;
4591                         gboolean is_ref = MONO_TYPE_IS_REFERENCE (fsig->params [1]);
4592                         if (fsig->params [1]->type == MONO_TYPE_I4)
4593                                 size = 4;
4594                         else if (is_ref || fsig->params [1]->type == MONO_TYPE_I)
4595                                 size = sizeof (gpointer);
4596                         else if (sizeof (gpointer) == 8 && fsig->params [1]->type == MONO_TYPE_I8)
4597                                 size = 8;
4598                         if (size == 4) {
4599                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I4);
4600                                 ins->dreg = alloc_ireg (cfg);
4601                                 ins->sreg1 = args [0]->dreg;
4602                                 ins->sreg2 = args [1]->dreg;
4603                                 ins->sreg3 = args [2]->dreg;
4604                                 ins->type = STACK_I4;
4605                                 MONO_ADD_INS (cfg->cbb, ins);
4606                         } else if (size == 8) {
4607                                 MONO_INST_NEW (cfg, ins, OP_ATOMIC_CAS_I8);
4608                                 ins->dreg = alloc_ireg (cfg);
4609                                 ins->sreg1 = args [0]->dreg;
4610                                 ins->sreg2 = args [1]->dreg;
4611                                 ins->sreg3 = args [2]->dreg;
4612                                 ins->type = STACK_I8;
4613                                 MONO_ADD_INS (cfg->cbb, ins);
4614                         } else {
4615                                 /* g_assert_not_reached (); */
4616                         }
4617                         if (cfg->gen_write_barriers && is_ref)
4618                                 emit_write_barrier (cfg, args [0], args [1], -1);
4619                 }
4620 #endif /* MONO_ARCH_HAVE_ATOMIC_CAS */
4621
4622                 if (ins)
4623                         return ins;
4624         } else if (cmethod->klass->image == mono_defaults.corlib) {
4625                 if (cmethod->name [0] == 'B' && strcmp (cmethod->name, "Break") == 0
4626                                 && strcmp (cmethod->klass->name, "Debugger") == 0) {
4627                         if (should_insert_brekpoint (cfg->method))
4628                                 MONO_INST_NEW (cfg, ins, OP_BREAK);
4629                         else
4630                                 MONO_INST_NEW (cfg, ins, OP_NOP);
4631                         MONO_ADD_INS (cfg->cbb, ins);
4632                         return ins;
4633                 }
4634                 if (cmethod->name [0] == 'g' && strcmp (cmethod->name, "get_IsRunningOnWindows") == 0
4635                                 && strcmp (cmethod->klass->name, "Environment") == 0) {
4636 #ifdef TARGET_WIN32
4637                         EMIT_NEW_ICONST (cfg, ins, 1);
4638 #else
4639                         EMIT_NEW_ICONST (cfg, ins, 0);
4640 #endif
4641                         return ins;
4642                 }
4643         } else if (cmethod->klass == mono_defaults.math_class) {
4644                 /* 
4645                  * There is general branches code for Min/Max, but it does not work for 
4646                  * all inputs:
4647                  * http://everything2.com/?node_id=1051618
4648                  */
4649         }
4650
4651 #ifdef MONO_ARCH_SIMD_INTRINSICS
4652         if (cfg->opt & MONO_OPT_SIMD) {
4653                 ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args);
4654                 if (ins)
4655                         return ins;
4656         }
4657 #endif
4658
4659         return mono_arch_emit_inst_for_method (cfg, cmethod, fsig, args);
4660 }
4661
4662 /*
4663  * This entry point could be used later for arbitrary method
4664  * redirection.
4665  */
4666 inline static MonoInst*
4667 mini_redirect_call (MonoCompile *cfg, MonoMethod *method,  
4668                                         MonoMethodSignature *signature, MonoInst **args, MonoInst *this)
4669 {
4670         if (method->klass == mono_defaults.string_class) {
4671                 /* managed string allocation support */
4672                 if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) {
4673                         MonoInst *iargs [2];
4674                         MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass);
4675                         MonoMethod *managed_alloc = NULL;
4676
4677                         g_assert (vtable); /*Should not fail since it System.String*/
4678 #ifndef MONO_CROSS_COMPILE
4679                         managed_alloc = mono_gc_get_managed_allocator (vtable, FALSE);
4680 #endif
4681                         if (!managed_alloc)
4682                                 return NULL;
4683                         EMIT_NEW_VTABLECONST (cfg, iargs [0], vtable);
4684                         iargs [1] = args [0];
4685                         return mono_emit_method_call (cfg, managed_alloc, iargs, this);
4686                 }
4687         }
4688         return NULL;
4689 }
4690
4691 static void
4692 mono_save_args (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **sp)
4693 {
4694         MonoInst *store, *temp;
4695         int i;
4696
4697         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4698                 MonoType *argtype = (sig->hasthis && (i == 0)) ? type_from_stack_type (*sp) : sig->params [i - sig->hasthis];
4699
4700                 /*
4701                  * FIXME: We should use *args++ = sp [0], but that would mean the arg
4702                  * would be different than the MonoInst's used to represent arguments, and
4703                  * the ldelema implementation can't deal with that.
4704                  * Solution: When ldelema is used on an inline argument, create a var for 
4705                  * it, emit ldelema on that var, and emit the saving code below in
4706                  * inline_method () if needed.
4707                  */
4708                 temp = mono_compile_create_var (cfg, argtype, OP_LOCAL);
4709                 cfg->args [i] = temp;
4710                 /* This uses cfg->args [i] which is set by the preceeding line */
4711                 EMIT_NEW_ARGSTORE (cfg, store, i, *sp);
4712                 store->cil_code = sp [0]->cil_code;
4713                 sp++;
4714         }
4715 }
4716
4717 #define MONO_INLINE_CALLED_LIMITED_METHODS 1
4718 #define MONO_INLINE_CALLER_LIMITED_METHODS 1
4719
4720 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4721 static gboolean
4722 check_inline_called_method_name_limit (MonoMethod *called_method)
4723 {
4724         int strncmp_result;
4725         static char *limit = NULL;
4726         
4727         if (limit == NULL) {
4728                 char *limit_string = getenv ("MONO_INLINE_CALLED_METHOD_NAME_LIMIT");
4729
4730                 if (limit_string != NULL)
4731                         limit = limit_string;
4732                 else
4733                         limit = (char *) "";
4734         }
4735
4736         if (limit [0] != '\0') {
4737                 char *called_method_name = mono_method_full_name (called_method, TRUE);
4738
4739                 strncmp_result = strncmp (called_method_name, limit, strlen (limit));
4740                 g_free (called_method_name);
4741         
4742                 //return (strncmp_result <= 0);
4743                 return (strncmp_result == 0);
4744         } else {
4745                 return TRUE;
4746         }
4747 }
4748 #endif
4749
4750 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4751 static gboolean
4752 check_inline_caller_method_name_limit (MonoMethod *caller_method)
4753 {
4754         int strncmp_result;
4755         static char *limit = NULL;
4756         
4757         if (limit == NULL) {
4758                 char *limit_string = getenv ("MONO_INLINE_CALLER_METHOD_NAME_LIMIT");
4759                 if (limit_string != NULL) {
4760                         limit = limit_string;
4761                 } else {
4762                         limit = (char *) "";
4763                 }
4764         }
4765
4766         if (limit [0] != '\0') {
4767                 char *caller_method_name = mono_method_full_name (caller_method, TRUE);
4768
4769                 strncmp_result = strncmp (caller_method_name, limit, strlen (limit));
4770                 g_free (caller_method_name);
4771         
4772                 //return (strncmp_result <= 0);
4773                 return (strncmp_result == 0);
4774         } else {
4775                 return TRUE;
4776         }
4777 }
4778 #endif
4779
4780 static int
4781 inline_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **sp,
4782                 guchar *ip, guint real_offset, GList *dont_inline, gboolean inline_always)
4783 {
4784         MonoInst *ins, *rvar = NULL;
4785         MonoMethodHeader *cheader;
4786         MonoBasicBlock *ebblock, *sbblock;
4787         int i, costs;
4788         MonoMethod *prev_inlined_method;
4789         MonoInst **prev_locals, **prev_args;
4790         MonoType **prev_arg_types;
4791         guint prev_real_offset;
4792         GHashTable *prev_cbb_hash;
4793         MonoBasicBlock **prev_cil_offset_to_bb;
4794         MonoBasicBlock *prev_cbb;
4795         unsigned char* prev_cil_start;
4796         guint32 prev_cil_offset_to_bb_len;
4797         MonoMethod *prev_current_method;
4798         MonoGenericContext *prev_generic_context;
4799         gboolean ret_var_set, prev_ret_var_set;
4800
4801         g_assert (cfg->exception_type == MONO_EXCEPTION_NONE);
4802
4803 #if (MONO_INLINE_CALLED_LIMITED_METHODS)
4804         if ((! inline_always) && ! check_inline_called_method_name_limit (cmethod))
4805                 return 0;
4806 #endif
4807 #if (MONO_INLINE_CALLER_LIMITED_METHODS)
4808         if ((! inline_always) && ! check_inline_caller_method_name_limit (cfg->method))
4809                 return 0;
4810 #endif
4811
4812         if (cfg->verbose_level > 2)
4813                 printf ("INLINE START %p %s -> %s\n", cmethod,  mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4814
4815         if (!cmethod->inline_info) {
4816                 mono_jit_stats.inlineable_methods++;
4817                 cmethod->inline_info = 1;
4818         }
4819
4820         /* allocate local variables */
4821         cheader = mono_method_get_header (cmethod);
4822
4823         if (cheader == NULL || mono_loader_get_last_error ()) {
4824                 MonoLoaderError *error = mono_loader_get_last_error ();
4825
4826                 if (cheader)
4827                         mono_metadata_free_mh (cheader);
4828                 if (inline_always && error)
4829                         mono_cfg_set_exception (cfg, error->exception_type);
4830
4831                 mono_loader_clear_error ();
4832                 return 0;
4833         }
4834
4835         /*Must verify before creating locals as it can cause the JIT to assert.*/
4836         if (mono_compile_is_broken (cfg, cmethod, FALSE)) {
4837                 mono_metadata_free_mh (cheader);
4838                 return 0;
4839         }
4840
4841         /* allocate space to store the return value */
4842         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
4843                 rvar = mono_compile_create_var (cfg, fsig->ret, OP_LOCAL);
4844         }
4845
4846
4847         prev_locals = cfg->locals;
4848         cfg->locals = mono_mempool_alloc0 (cfg->mempool, cheader->num_locals * sizeof (MonoInst*));     
4849         for (i = 0; i < cheader->num_locals; ++i)
4850                 cfg->locals [i] = mono_compile_create_var (cfg, cheader->locals [i], OP_LOCAL);
4851
4852         /* allocate start and end blocks */
4853         /* This is needed so if the inline is aborted, we can clean up */
4854         NEW_BBLOCK (cfg, sbblock);
4855         sbblock->real_offset = real_offset;
4856
4857         NEW_BBLOCK (cfg, ebblock);
4858         ebblock->block_num = cfg->num_bblocks++;
4859         ebblock->real_offset = real_offset;
4860
4861         prev_args = cfg->args;
4862         prev_arg_types = cfg->arg_types;
4863         prev_inlined_method = cfg->inlined_method;
4864         cfg->inlined_method = cmethod;
4865         cfg->ret_var_set = FALSE;
4866         cfg->inline_depth ++;
4867         prev_real_offset = cfg->real_offset;
4868         prev_cbb_hash = cfg->cbb_hash;
4869         prev_cil_offset_to_bb = cfg->cil_offset_to_bb;
4870         prev_cil_offset_to_bb_len = cfg->cil_offset_to_bb_len;
4871         prev_cil_start = cfg->cil_start;
4872         prev_cbb = cfg->cbb;
4873         prev_current_method = cfg->current_method;
4874         prev_generic_context = cfg->generic_context;
4875         prev_ret_var_set = cfg->ret_var_set;
4876
4877         costs = mono_method_to_ir (cfg, cmethod, sbblock, ebblock, rvar, dont_inline, sp, real_offset, *ip == CEE_CALLVIRT);
4878
4879         ret_var_set = cfg->ret_var_set;
4880
4881         cfg->inlined_method = prev_inlined_method;
4882         cfg->real_offset = prev_real_offset;
4883         cfg->cbb_hash = prev_cbb_hash;
4884         cfg->cil_offset_to_bb = prev_cil_offset_to_bb;
4885         cfg->cil_offset_to_bb_len = prev_cil_offset_to_bb_len;
4886         cfg->cil_start = prev_cil_start;
4887         cfg->locals = prev_locals;
4888         cfg->args = prev_args;
4889         cfg->arg_types = prev_arg_types;
4890         cfg->current_method = prev_current_method;
4891         cfg->generic_context = prev_generic_context;
4892         cfg->ret_var_set = prev_ret_var_set;
4893         cfg->inline_depth --;
4894
4895         if ((costs >= 0 && costs < 60) || inline_always) {
4896                 if (cfg->verbose_level > 2)
4897                         printf ("INLINE END %s -> %s\n", mono_method_full_name (cfg->method, TRUE), mono_method_full_name (cmethod, TRUE));
4898                 
4899                 mono_jit_stats.inlined_methods++;
4900
4901                 /* always add some code to avoid block split failures */
4902                 MONO_INST_NEW (cfg, ins, OP_NOP);
4903                 MONO_ADD_INS (prev_cbb, ins);
4904
4905                 prev_cbb->next_bb = sbblock;
4906                 link_bblock (cfg, prev_cbb, sbblock);
4907
4908                 /* 
4909                  * Get rid of the begin and end bblocks if possible to aid local
4910                  * optimizations.
4911                  */
4912                 mono_merge_basic_blocks (cfg, prev_cbb, sbblock);
4913
4914                 if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] != ebblock))
4915                         mono_merge_basic_blocks (cfg, prev_cbb, prev_cbb->out_bb [0]);
4916
4917                 if ((ebblock->in_count == 1) && ebblock->in_bb [0]->out_count == 1) {
4918                         MonoBasicBlock *prev = ebblock->in_bb [0];
4919                         mono_merge_basic_blocks (cfg, prev, ebblock);
4920                         cfg->cbb = prev;
4921                         if ((prev_cbb->out_count == 1) && (prev_cbb->out_bb [0]->in_count == 1) && (prev_cbb->out_bb [0] == prev)) {
4922                                 mono_merge_basic_blocks (cfg, prev_cbb, prev);
4923                                 cfg->cbb = prev_cbb;
4924                         }
4925                 } else {
4926                         cfg->cbb = ebblock;
4927                 }
4928
4929                 if (rvar) {
4930                         /*
4931                          * If the inlined method contains only a throw, then the ret var is not 
4932                          * set, so set it to a dummy value.
4933                          */
4934                         if (!ret_var_set) {
4935                                 static double r8_0 = 0.0;
4936
4937                                 switch (rvar->type) {
4938                                 case STACK_I4:
4939                                         MONO_EMIT_NEW_ICONST (cfg, rvar->dreg, 0);
4940                                         break;
4941                                 case STACK_I8:
4942                                         MONO_EMIT_NEW_I8CONST (cfg, rvar->dreg, 0);
4943                                         break;
4944                                 case STACK_PTR:
4945                                 case STACK_MP:
4946                                 case STACK_OBJ:
4947                                         MONO_EMIT_NEW_PCONST (cfg, rvar->dreg, 0);
4948                                         break;
4949                                 case STACK_R8:
4950                                         MONO_INST_NEW (cfg, ins, OP_R8CONST);
4951                                         ins->type = STACK_R8;
4952                                         ins->inst_p0 = (void*)&r8_0;
4953                                         ins->dreg = rvar->dreg;
4954                                         MONO_ADD_INS (cfg->cbb, ins);
4955                                         break;
4956                                 case STACK_VTYPE:
4957                                         MONO_EMIT_NEW_VZERO (cfg, rvar->dreg, mono_class_from_mono_type (fsig->ret));
4958                                         break;
4959                                 default:
4960                                         g_assert_not_reached ();
4961                                 }
4962                         }
4963
4964                         EMIT_NEW_TEMPLOAD (cfg, ins, rvar->inst_c0);
4965                         *sp++ = ins;
4966                 }
4967                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
4968                 return costs + 1;
4969         } else {
4970                 if (cfg->verbose_level > 2)
4971                         printf ("INLINE ABORTED %s\n", mono_method_full_name (cmethod, TRUE));
4972                 cfg->exception_type = MONO_EXCEPTION_NONE;
4973                 mono_loader_clear_error ();
4974
4975                 /* This gets rid of the newly added bblocks */
4976                 cfg->cbb = prev_cbb;
4977         }
4978         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, cheader);
4979         return 0;
4980 }
4981
4982 /*
4983  * Some of these comments may well be out-of-date.
4984  * Design decisions: we do a single pass over the IL code (and we do bblock 
4985  * splitting/merging in the few cases when it's required: a back jump to an IL
4986  * address that was not already seen as bblock starting point).
4987  * Code is validated as we go (full verification is still better left to metadata/verify.c).
4988  * Complex operations are decomposed in simpler ones right away. We need to let the 
4989  * arch-specific code peek and poke inside this process somehow (except when the 
4990  * optimizations can take advantage of the full semantic info of coarse opcodes).
4991  * All the opcodes of the form opcode.s are 'normalized' to opcode.
4992  * MonoInst->opcode initially is the IL opcode or some simplification of that 
4993  * (OP_LOAD, OP_STORE). The arch-specific code may rearrange it to an arch-specific 
4994  * opcode with value bigger than OP_LAST.
4995  * At this point the IR can be handed over to an interpreter, a dumb code generator
4996  * or to the optimizing code generator that will translate it to SSA form.
4997  *
4998  * Profiling directed optimizations.
4999  * We may compile by default with few or no optimizations and instrument the code
5000  * or the user may indicate what methods to optimize the most either in a config file
5001  * or through repeated runs where the compiler applies offline the optimizations to 
5002  * each method and then decides if it was worth it.
5003  */
5004
5005 #define CHECK_TYPE(ins) if (!(ins)->type) UNVERIFIED
5006 #define CHECK_STACK(num) if ((sp - stack_start) < (num)) UNVERIFIED
5007 #define CHECK_STACK_OVF(num) if (((sp - stack_start) + (num)) > header->max_stack) UNVERIFIED
5008 #define CHECK_ARG(num) if ((unsigned)(num) >= (unsigned)num_args) UNVERIFIED
5009 #define CHECK_LOCAL(num) if ((unsigned)(num) >= (unsigned)header->num_locals) UNVERIFIED
5010 #define CHECK_OPSIZE(size) if (ip + size > end) UNVERIFIED
5011 #define CHECK_UNVERIFIABLE(cfg) if (cfg->unverifiable) UNVERIFIED
5012 #define CHECK_TYPELOAD(klass) if (!(klass) || (klass)->exception_type) {cfg->exception_ptr = klass; LOAD_ERROR;}
5013
5014 /* offset from br.s -> br like opcodes */
5015 #define BIG_BRANCH_OFFSET 13
5016
5017 static gboolean
5018 ip_in_bb (MonoCompile *cfg, MonoBasicBlock *bb, const guint8* ip)
5019 {
5020         MonoBasicBlock *b = cfg->cil_offset_to_bb [ip - cfg->cil_start];
5021
5022         return b == NULL || b == bb;
5023 }
5024
5025 static int
5026 get_basic_blocks (MonoCompile *cfg, MonoMethodHeader* header, guint real_offset, unsigned char *start, unsigned char *end, unsigned char **pos)
5027 {
5028         unsigned char *ip = start;
5029         unsigned char *target;
5030         int i;
5031         guint cli_addr;
5032         MonoBasicBlock *bblock;
5033         const MonoOpcode *opcode;
5034
5035         while (ip < end) {
5036                 cli_addr = ip - start;
5037                 i = mono_opcode_value ((const guint8 **)&ip, end);
5038                 if (i < 0)
5039                         UNVERIFIED;
5040                 opcode = &mono_opcodes [i];
5041                 switch (opcode->argument) {
5042                 case MonoInlineNone:
5043                         ip++; 
5044                         break;
5045                 case MonoInlineString:
5046                 case MonoInlineType:
5047                 case MonoInlineField:
5048                 case MonoInlineMethod:
5049                 case MonoInlineTok:
5050                 case MonoInlineSig:
5051                 case MonoShortInlineR:
5052                 case MonoInlineI:
5053                         ip += 5;
5054                         break;
5055                 case MonoInlineVar:
5056                         ip += 3;
5057                         break;
5058                 case MonoShortInlineVar:
5059                 case MonoShortInlineI:
5060                         ip += 2;
5061                         break;
5062                 case MonoShortInlineBrTarget:
5063                         target = start + cli_addr + 2 + (signed char)ip [1];
5064                         GET_BBLOCK (cfg, bblock, target);
5065                         ip += 2;
5066                         if (ip < end)
5067                                 GET_BBLOCK (cfg, bblock, ip);
5068                         break;
5069                 case MonoInlineBrTarget:
5070                         target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
5071                         GET_BBLOCK (cfg, bblock, target);
5072                         ip += 5;
5073                         if (ip < end)
5074                                 GET_BBLOCK (cfg, bblock, ip);
5075                         break;
5076                 case MonoInlineSwitch: {
5077                         guint32 n = read32 (ip + 1);
5078                         guint32 j;
5079                         ip += 5;
5080                         cli_addr += 5 + 4 * n;
5081                         target = start + cli_addr;
5082                         GET_BBLOCK (cfg, bblock, target);
5083                         
5084                         for (j = 0; j < n; ++j) {
5085                                 target = start + cli_addr + (gint32)read32 (ip);
5086                                 GET_BBLOCK (cfg, bblock, target);
5087                                 ip += 4;
5088                         }
5089                         break;
5090                 }
5091                 case MonoInlineR:
5092                 case MonoInlineI8:
5093                         ip += 9;
5094                         break;
5095                 default:
5096                         g_assert_not_reached ();
5097                 }
5098
5099                 if (i == CEE_THROW) {
5100                         unsigned char *bb_start = ip - 1;
5101                         
5102                         /* Find the start of the bblock containing the throw */
5103                         bblock = NULL;
5104                         while ((bb_start >= start) && !bblock) {
5105                                 bblock = cfg->cil_offset_to_bb [(bb_start) - start];
5106                                 bb_start --;
5107                         }
5108                         if (bblock)
5109                                 bblock->out_of_line = 1;
5110                 }
5111         }
5112         return 0;
5113 unverified:
5114         *pos = ip;
5115         return 1;
5116 }
5117
5118 static inline MonoMethod *
5119 mini_get_method_allow_open (MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
5120 {
5121         MonoMethod *method;
5122
5123         if (m->wrapper_type != MONO_WRAPPER_NONE)
5124                 return mono_method_get_wrapper_data (m, token);
5125
5126         method = mono_get_method_full (m->klass->image, token, klass, context);
5127
5128         return method;
5129 }
5130
5131 static inline MonoMethod *
5132 mini_get_method (MonoCompile *cfg, MonoMethod *m, guint32 token, MonoClass *klass, MonoGenericContext *context)
5133 {
5134         MonoMethod *method = mini_get_method_allow_open (m, token, klass, context);
5135
5136         if (method && cfg && !cfg->generic_sharing_context && mono_class_is_open_constructed_type (&method->klass->byval_arg))
5137                 return NULL;
5138
5139         return method;
5140 }
5141
5142 static inline MonoClass*
5143 mini_get_class (MonoMethod *method, guint32 token, MonoGenericContext *context)
5144 {
5145         MonoClass *klass;
5146
5147         if (method->wrapper_type != MONO_WRAPPER_NONE)
5148                 klass = mono_method_get_wrapper_data (method, token);
5149         else
5150                 klass = mono_class_get_full (method->klass->image, token, context);
5151         if (klass)
5152                 mono_class_init (klass);
5153         return klass;
5154 }
5155
5156 /*
5157  * Returns TRUE if the JIT should abort inlining because "callee"
5158  * is influenced by security attributes.
5159  */
5160 static
5161 gboolean check_linkdemand (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee)
5162 {
5163         guint32 result;
5164         
5165         if ((cfg->method != caller) && mono_method_has_declsec (callee)) {
5166                 return TRUE;
5167         }
5168         
5169         result = mono_declsec_linkdemand (cfg->domain, caller, callee);
5170         if (result == MONO_JIT_SECURITY_OK)
5171                 return FALSE;
5172
5173         if (result == MONO_JIT_LINKDEMAND_ECMA) {
5174                 /* Generate code to throw a SecurityException before the actual call/link */
5175                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
5176                 MonoInst *args [2];
5177
5178                 NEW_ICONST (cfg, args [0], 4);
5179                 NEW_METHODCONST (cfg, args [1], caller);
5180                 mono_emit_method_call (cfg, secman->linkdemandsecurityexception, args, NULL);
5181         } else if (cfg->exception_type == MONO_EXCEPTION_NONE) {
5182                  /* don't hide previous results */
5183                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_SECURITY_LINKDEMAND);
5184                 cfg->exception_data = result;
5185                 return TRUE;
5186         }
5187         
5188         return FALSE;
5189 }
5190
5191 static MonoMethod*
5192 throw_exception (void)
5193 {
5194         static MonoMethod *method = NULL;
5195
5196         if (!method) {
5197                 MonoSecurityManager *secman = mono_security_manager_get_methods ();
5198                 method = mono_class_get_method_from_name (secman->securitymanager, "ThrowException", 1);
5199         }
5200         g_assert (method);
5201         return method;
5202 }
5203
5204 static void
5205 emit_throw_exception (MonoCompile *cfg, MonoException *ex)
5206 {
5207         MonoMethod *thrower = throw_exception ();
5208         MonoInst *args [1];
5209
5210         EMIT_NEW_PCONST (cfg, args [0], ex);
5211         mono_emit_method_call (cfg, thrower, args, NULL);
5212 }
5213
5214 /*
5215  * Return the original method is a wrapper is specified. We can only access 
5216  * the custom attributes from the original method.
5217  */
5218 static MonoMethod*
5219 get_original_method (MonoMethod *method)
5220 {
5221         if (method->wrapper_type == MONO_WRAPPER_NONE)
5222                 return method;
5223
5224         /* native code (which is like Critical) can call any managed method XXX FIXME XXX to validate all usages */
5225         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED)
5226                 return NULL;
5227
5228         /* in other cases we need to find the original method */
5229         return mono_marshal_method_from_wrapper (method);
5230 }
5231
5232 static void
5233 ensure_method_is_allowed_to_access_field (MonoCompile *cfg, MonoMethod *caller, MonoClassField *field,
5234                                           MonoBasicBlock *bblock, unsigned char *ip)
5235 {
5236         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
5237         MonoException *ex = mono_security_core_clr_is_field_access_allowed (get_original_method (caller), field);
5238         if (ex)
5239                 emit_throw_exception (cfg, ex);
5240 }
5241
5242 static void
5243 ensure_method_is_allowed_to_call_method (MonoCompile *cfg, MonoMethod *caller, MonoMethod *callee,
5244                                          MonoBasicBlock *bblock, unsigned char *ip)
5245 {
5246         /* we can't get the coreclr security level on wrappers since they don't have the attributes */
5247         MonoException *ex = mono_security_core_clr_is_call_allowed (get_original_method (caller), callee);
5248         if (ex)
5249                 emit_throw_exception (cfg, ex);
5250 }
5251
5252 /*
5253  * Check that the IL instructions at ip are the array initialization
5254  * sequence and return the pointer to the data and the size.
5255  */
5256 static const char*
5257 initialize_array_data (MonoMethod *method, gboolean aot, unsigned char *ip, MonoClass *klass, guint32 len, int *out_size, guint32 *out_field_token)
5258 {
5259         /*
5260          * newarr[System.Int32]
5261          * dup
5262          * ldtoken field valuetype ...
5263          * call void class [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype [mscorlib]System.RuntimeFieldHandle)
5264          */
5265         if (ip [0] == CEE_DUP && ip [1] == CEE_LDTOKEN && ip [5] == 0x4 && ip [6] == CEE_CALL) {
5266                 guint32 token = read32 (ip + 7);
5267                 guint32 field_token = read32 (ip + 2);
5268                 guint32 field_index = field_token & 0xffffff;
5269                 guint32 rva;
5270                 const char *data_ptr;
5271                 int size = 0;
5272                 MonoMethod *cmethod;
5273                 MonoClass *dummy_class;
5274                 MonoClassField *field = mono_field_from_token (method->klass->image, field_token, &dummy_class, NULL);
5275                 int dummy_align;
5276
5277                 if (!field)
5278                         return NULL;
5279
5280                 *out_field_token = field_token;
5281
5282                 cmethod = mini_get_method (NULL, method, token, NULL, NULL);
5283                 if (!cmethod)
5284                         return NULL;
5285                 if (strcmp (cmethod->name, "InitializeArray") || strcmp (cmethod->klass->name, "RuntimeHelpers") || cmethod->klass->image != mono_defaults.corlib)
5286                         return NULL;
5287                 switch (mono_type_get_underlying_type (&klass->byval_arg)->type) {
5288                 case MONO_TYPE_BOOLEAN:
5289                 case MONO_TYPE_I1:
5290                 case MONO_TYPE_U1:
5291                         size = 1; break;
5292                 /* we need to swap on big endian, so punt. Should we handle R4 and R8 as well? */
5293 #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN
5294                 case MONO_TYPE_CHAR:
5295                 case MONO_TYPE_I2:
5296                 case MONO_TYPE_U2:
5297                         size = 2; break;
5298                 case MONO_TYPE_I4:
5299                 case MONO_TYPE_U4:
5300                 case MONO_TYPE_R4:
5301                         size = 4; break;
5302                 case MONO_TYPE_R8:
5303 #ifdef ARM_FPU_FPA
5304                         return NULL; /* stupid ARM FP swapped format */
5305 #endif
5306                 case MONO_TYPE_I8:
5307                 case MONO_TYPE_U8:
5308                         size = 8; break;
5309 #endif
5310                 default:
5311                         return NULL;
5312                 }
5313                 size *= len;
5314                 if (size > mono_type_size (field->type, &dummy_align))
5315                     return NULL;
5316                 *out_size = size;
5317                 /*g_print ("optimized in %s: size: %d, numelems: %d\n", method->name, size, newarr->inst_newa_len->inst_c0);*/
5318                 if (!method->klass->image->dynamic) {
5319                         field_index = read32 (ip + 2) & 0xffffff;
5320                         mono_metadata_field_info (method->klass->image, field_index - 1, NULL, &rva, NULL);
5321                         data_ptr = mono_image_rva_map (method->klass->image, rva);
5322                         /*g_print ("field: 0x%08x, rva: %d, rva_ptr: %p\n", read32 (ip + 2), rva, data_ptr);*/
5323                         /* for aot code we do the lookup on load */
5324                         if (aot && data_ptr)
5325                                 return GUINT_TO_POINTER (rva);
5326                 } else {
5327                         /*FIXME is it possible to AOT a SRE assembly not meant to be saved? */ 
5328                         g_assert (!aot);
5329                         data_ptr = mono_field_get_data (field);
5330                 }
5331                 return data_ptr;
5332         }
5333         return NULL;
5334 }
5335
5336 static void
5337 set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsigned char *ip)
5338 {
5339         char *method_fname = mono_method_full_name (method, TRUE);
5340         char *method_code;
5341         MonoMethodHeader *header = mono_method_get_header (method);
5342
5343         if (header->code_size == 0)
5344                 method_code = g_strdup ("method body is empty.");
5345         else
5346                 method_code = mono_disasm_code_one (NULL, method, ip, NULL);
5347         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
5348         cfg->exception_message = g_strdup_printf ("Invalid IL code in %s: %s\n", method_fname, method_code);
5349         g_free (method_fname);
5350         g_free (method_code);
5351         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
5352 }
5353
5354 static void
5355 set_exception_object (MonoCompile *cfg, MonoException *exception)
5356 {
5357         mono_cfg_set_exception (cfg, MONO_EXCEPTION_OBJECT_SUPPLIED);
5358         MONO_GC_REGISTER_ROOT_SINGLE (cfg->exception_ptr);
5359         cfg->exception_ptr = exception;
5360 }
5361
5362 static gboolean
5363 generic_class_is_reference_type (MonoCompile *cfg, MonoClass *klass)
5364 {
5365         MonoType *type;
5366
5367         if (cfg->generic_sharing_context)
5368                 type = mini_get_basic_type_from_generic (cfg->generic_sharing_context, &klass->byval_arg);
5369         else
5370                 type = &klass->byval_arg;
5371         return MONO_TYPE_IS_REFERENCE (type);
5372 }
5373
5374 static void
5375 emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n)
5376 {
5377         MonoInst *ins;
5378         guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]);
5379         if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0]  &&
5380                         ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {
5381                 /* Optimize reg-reg moves away */
5382                 /* 
5383                  * Can't optimize other opcodes, since sp[0] might point to
5384                  * the last ins of a decomposed opcode.
5385                  */
5386                 sp [0]->dreg = (cfg)->locals [n]->dreg;
5387         } else {
5388                 EMIT_NEW_LOCSTORE (cfg, ins, n, *sp);
5389         }
5390 }
5391
5392 /*
5393  * ldloca inhibits many optimizations so try to get rid of it in common
5394  * cases.
5395  */
5396 static inline unsigned char *
5397 emit_optimized_ldloca_ir (MonoCompile *cfg, unsigned char *ip, unsigned char *end, int size)
5398 {
5399         int local, token;
5400         MonoClass *klass;
5401
5402         if (size == 1) {
5403                 local = ip [1];
5404                 ip += 2;
5405         } else {
5406                 local = read16 (ip + 2);
5407                 ip += 4;
5408         }
5409         
5410         if (ip + 6 < end && (ip [0] == CEE_PREFIX1) && (ip [1] == CEE_INITOBJ) && ip_in_bb (cfg, cfg->cbb, ip + 1)) {
5411                 gboolean skip = FALSE;
5412
5413                 /* From the INITOBJ case */
5414                 token = read32 (ip + 2);
5415                 klass = mini_get_class (cfg->current_method, token, cfg->generic_context);
5416                 CHECK_TYPELOAD (klass);
5417                 if (generic_class_is_reference_type (cfg, klass)) {
5418                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [local]->dreg, NULL);
5419                 } else if (MONO_TYPE_IS_REFERENCE (&klass->byval_arg)) {
5420                         MONO_EMIT_NEW_PCONST (cfg, cfg->locals [local]->dreg, NULL);
5421                 } else if (MONO_TYPE_ISSTRUCT (&klass->byval_arg)) {
5422                         MONO_EMIT_NEW_VZERO (cfg, cfg->locals [local]->dreg, klass);
5423                 } else {
5424                         skip = TRUE;
5425                 }
5426                         
5427                 if (!skip)
5428                         return ip + 6;
5429         }
5430 load_error:
5431         return NULL;
5432 }
5433
5434 static gboolean
5435 is_exception_class (MonoClass *class)
5436 {
5437         while (class) {
5438                 if (class == mono_defaults.exception_class)
5439                         return TRUE;
5440                 class = class->parent;
5441         }
5442         return FALSE;
5443 }
5444
5445 /*
5446  * is_jit_optimizer_disabled:
5447  *
5448  *   Determine whenever M's assembly has a DebuggableAttribute with the
5449  * IsJITOptimizerDisabled flag set.
5450  */
5451 static gboolean
5452 is_jit_optimizer_disabled (MonoMethod *m)
5453 {
5454         MonoAssembly *ass = m->klass->image->assembly;
5455         MonoCustomAttrInfo* attrs;
5456         static MonoClass *klass;
5457         int i;
5458         gboolean val = FALSE;
5459
5460         g_assert (ass);
5461         if (ass->jit_optimizer_disabled_inited)
5462                 return ass->jit_optimizer_disabled;
5463
5464         klass = mono_class_from_name_cached (mono_defaults.corlib, "System.Diagnostics", "DebuggableAttribute");
5465
5466         attrs = mono_custom_attrs_from_assembly (ass);
5467         if (attrs) {
5468                 for (i = 0; i < attrs->num_attrs; ++i) {
5469                         MonoCustomAttrEntry *attr = &attrs->attrs [i];
5470                         const gchar *p;
5471                         int len;
5472                         MonoMethodSignature *sig;
5473
5474                         if (!attr->ctor || attr->ctor->klass != klass)
5475                                 continue;
5476                         /* Decode the attribute. See reflection.c */
5477                         len = attr->data_size;
5478                         p = (const char*)attr->data;
5479                         g_assert (read16 (p) == 0x0001);
5480                         p += 2;
5481
5482                         // FIXME: Support named parameters
5483                         sig = mono_method_signature (attr->ctor);
5484                         if (sig->param_count != 2 || sig->params [0]->type != MONO_TYPE_BOOLEAN || sig->params [1]->type != MONO_TYPE_BOOLEAN)
5485                                 continue;
5486                         /* Two boolean arguments */
5487                         p ++;
5488                         val = *p;
5489                 }
5490         }
5491
5492         ass->jit_optimizer_disabled = val;
5493         mono_memory_barrier ();
5494         ass->jit_optimizer_disabled_inited = TRUE;
5495
5496         return val;
5497 }
5498
5499 /*
5500  * mono_method_to_ir:
5501  *
5502  *   Translate the .net IL into linear IR.
5503  */
5504 int
5505 mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_bblock, MonoBasicBlock *end_bblock, 
5506                    MonoInst *return_var, GList *dont_inline, MonoInst **inline_args, 
5507                    guint inline_offset, gboolean is_virtual_call)
5508 {
5509         MonoError error;
5510         MonoInst *ins, **sp, **stack_start;
5511         MonoBasicBlock *bblock, *tblock = NULL, *init_localsbb = NULL;
5512         MonoSimpleBasicBlock *bb = NULL, *original_bb = NULL;
5513         MonoMethod *cmethod, *method_definition;
5514         MonoInst **arg_array;
5515         MonoMethodHeader *header;
5516         MonoImage *image;
5517         guint32 token, ins_flag;
5518         MonoClass *klass;
5519         MonoClass *constrained_call = NULL;
5520         unsigned char *ip, *end, *target, *err_pos;
5521         static double r8_0 = 0.0;
5522         MonoMethodSignature *sig;
5523         MonoGenericContext *generic_context = NULL;
5524         MonoGenericContainer *generic_container = NULL;
5525         MonoType **param_types;
5526         int i, n, start_new_bblock, dreg;
5527         int num_calls = 0, inline_costs = 0;
5528         int breakpoint_id = 0;
5529         guint num_args;
5530         MonoBoolean security, pinvoke;
5531         MonoSecurityManager* secman = NULL;
5532         MonoDeclSecurityActions actions;
5533         GSList *class_inits = NULL;
5534         gboolean dont_verify, dont_verify_stloc, readonly = FALSE;
5535         int context_used;
5536         gboolean init_locals, seq_points, skip_dead_blocks;
5537         gboolean disable_inline;
5538
5539         disable_inline = is_jit_optimizer_disabled (method);
5540
5541         /* serialization and xdomain stuff may need access to private fields and methods */
5542         dont_verify = method->klass->image->assembly->corlib_internal? TRUE: FALSE;
5543         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_INVOKE;
5544         dont_verify |= method->wrapper_type == MONO_WRAPPER_XDOMAIN_DISPATCH;
5545         dont_verify |= method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE; /* bug #77896 */
5546         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP;
5547         dont_verify |= method->wrapper_type == MONO_WRAPPER_COMINTEROP_INVOKE;
5548
5549         dont_verify |= mono_security_get_mode () == MONO_SECURITY_MODE_SMCS_HACK;
5550
5551         /* still some type unsafety issues in marshal wrappers... (unknown is PtrToStructure) */
5552         dont_verify_stloc = method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE;
5553         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_UNKNOWN;
5554         dont_verify_stloc |= method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED;
5555
5556         image = method->klass->image;
5557         header = mono_method_get_header (method);
5558         if (!header) {
5559                 MonoLoaderError *error;
5560
5561                 if ((error = mono_loader_get_last_error ())) {
5562                         mono_cfg_set_exception (cfg, error->exception_type);
5563                 } else {
5564                         mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
5565                         cfg->exception_message = g_strdup_printf ("Missing or incorrect header for method %s", cfg->method->name);
5566                 }
5567                 goto exception_exit;
5568         }
5569         generic_container = mono_method_get_generic_container (method);
5570         sig = mono_method_signature (method);
5571         num_args = sig->hasthis + sig->param_count;
5572         ip = (unsigned char*)header->code;
5573         cfg->cil_start = ip;
5574         end = ip + header->code_size;
5575         mono_jit_stats.cil_code_size += header->code_size;
5576         init_locals = header->init_locals;
5577
5578         seq_points = cfg->gen_seq_points && cfg->method == method;
5579
5580         /* 
5581          * Methods without init_locals set could cause asserts in various passes
5582          * (#497220).
5583          */
5584         init_locals = TRUE;
5585
5586         method_definition = method;
5587         while (method_definition->is_inflated) {
5588                 MonoMethodInflated *imethod = (MonoMethodInflated *) method_definition;
5589                 method_definition = imethod->declaring;
5590         }
5591
5592         /* SkipVerification is not allowed if core-clr is enabled */
5593         if (!dont_verify && mini_assembly_can_skip_verification (cfg->domain, method)) {
5594                 dont_verify = TRUE;
5595                 dont_verify_stloc = TRUE;
5596         }
5597
5598         if (mono_debug_using_mono_debugger ())
5599                 cfg->keep_cil_nops = TRUE;
5600
5601         if (sig->is_inflated)
5602                 generic_context = mono_method_get_context (method);
5603         else if (generic_container)
5604                 generic_context = &generic_container->context;
5605         cfg->generic_context = generic_context;
5606
5607         if (!cfg->generic_sharing_context)
5608                 g_assert (!sig->has_type_parameters);
5609
5610         if (sig->generic_param_count && method->wrapper_type == MONO_WRAPPER_NONE) {
5611                 g_assert (method->is_inflated);
5612                 g_assert (mono_method_get_context (method)->method_inst);
5613         }
5614         if (method->is_inflated && mono_method_get_context (method)->method_inst)
5615                 g_assert (sig->generic_param_count);
5616
5617         if (cfg->method == method) {
5618                 cfg->real_offset = 0;
5619         } else {
5620                 cfg->real_offset = inline_offset;
5621         }
5622
5623         cfg->cil_offset_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoBasicBlock*) * header->code_size);
5624         cfg->cil_offset_to_bb_len = header->code_size;
5625
5626         cfg->current_method = method;
5627
5628         if (cfg->verbose_level > 2)
5629                 printf ("method to IR %s\n", mono_method_full_name (method, TRUE));
5630
5631         param_types = mono_mempool_alloc (cfg->mempool, sizeof (MonoType*) * num_args);
5632         if (sig->hasthis)
5633                 param_types [0] = method->klass->valuetype?&method->klass->this_arg:&method->klass->byval_arg;
5634         for (n = 0; n < sig->param_count; ++n)
5635                 param_types [n + sig->hasthis] = sig->params [n];
5636         cfg->arg_types = param_types;
5637
5638         dont_inline = g_list_prepend (dont_inline, method);
5639         if (cfg->method == method) {
5640
5641                 if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE)
5642                         cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size);
5643
5644                 /* ENTRY BLOCK */
5645                 NEW_BBLOCK (cfg, start_bblock);
5646                 cfg->bb_entry = start_bblock;
5647                 start_bblock->cil_code = NULL;
5648                 start_bblock->cil_length = 0;
5649
5650                 /* EXIT BLOCK */
5651                 NEW_BBLOCK (cfg, end_bblock);
5652                 cfg->bb_exit = end_bblock;
5653                 end_bblock->cil_code = NULL;
5654                 end_bblock->cil_length = 0;
5655                 end_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
5656                 g_assert (cfg->num_bblocks == 2);
5657
5658                 arg_array = cfg->args;
5659
5660                 if (header->num_clauses) {
5661                         cfg->spvars = g_hash_table_new (NULL, NULL);
5662                         cfg->exvars = g_hash_table_new (NULL, NULL);
5663                 }
5664                 /* handle exception clauses */
5665                 for (i = 0; i < header->num_clauses; ++i) {
5666                         MonoBasicBlock *try_bb;
5667                         MonoExceptionClause *clause = &header->clauses [i];
5668                         GET_BBLOCK (cfg, try_bb, ip + clause->try_offset);
5669                         try_bb->real_offset = clause->try_offset;
5670                         try_bb->try_start = TRUE;
5671                         try_bb->region = ((i + 1) << 8) | clause->flags;
5672                         GET_BBLOCK (cfg, tblock, ip + clause->handler_offset);
5673                         tblock->real_offset = clause->handler_offset;
5674                         tblock->flags |= BB_EXCEPTION_HANDLER;
5675
5676                         link_bblock (cfg, try_bb, tblock);
5677
5678                         if (*(ip + clause->handler_offset) == CEE_POP)
5679                                 tblock->flags |= BB_EXCEPTION_DEAD_OBJ;
5680
5681                         if (clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY ||
5682                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER ||
5683                             clause->flags == MONO_EXCEPTION_CLAUSE_FAULT) {
5684                                 if (seq_points) {
5685                                         NEW_SEQ_POINT (cfg, ins, clause->handler_offset, TRUE);
5686                                         MONO_ADD_INS (tblock, ins);
5687                                 }
5688                                 MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5689                                 MONO_ADD_INS (tblock, ins);
5690
5691                                 /* todo: is a fault block unsafe to optimize? */
5692                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FAULT)
5693                                         tblock->flags |= BB_EXCEPTION_UNSAFE;
5694                         }
5695
5696
5697                         /*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);
5698                           while (p < end) {
5699                           printf ("%s", mono_disasm_code_one (NULL, method, p, &p));
5700                           }*/
5701                         /* catch and filter blocks get the exception object on the stack */
5702                         if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE ||
5703                             clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5704                                 MonoInst *dummy_use;
5705
5706                                 /* mostly like handle_stack_args (), but just sets the input args */
5707                                 /* printf ("handling clause at IL_%04x\n", clause->handler_offset); */
5708                                 tblock->in_scount = 1;
5709                                 tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5710                                 tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5711
5712                                 /* 
5713                                  * Add a dummy use for the exvar so its liveness info will be
5714                                  * correct.
5715                                  */
5716                                 cfg->cbb = tblock;
5717                                 EMIT_NEW_DUMMY_USE (cfg, dummy_use, tblock->in_stack [0]);
5718                                 
5719                                 if (clause->flags == MONO_EXCEPTION_CLAUSE_FILTER) {
5720                                         GET_BBLOCK (cfg, tblock, ip + clause->data.filter_offset);
5721                                         tblock->flags |= BB_EXCEPTION_HANDLER;
5722                                         tblock->real_offset = clause->data.filter_offset;
5723                                         tblock->in_scount = 1;
5724                                         tblock->in_stack = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*));
5725                                         /* The filter block shares the exvar with the handler block */
5726                                         tblock->in_stack [0] = mono_create_exvar_for_offset (cfg, clause->handler_offset);
5727                                         MONO_INST_NEW (cfg, ins, OP_START_HANDLER);
5728                                         MONO_ADD_INS (tblock, ins);
5729                                 }
5730                         }
5731
5732                         if (clause->flags != MONO_EXCEPTION_CLAUSE_FILTER &&
5733                                         clause->data.catch_class &&
5734                                         cfg->generic_sharing_context &&
5735                                         mono_class_check_context_used (clause->data.catch_class)) {
5736                                 /*
5737                                  * In shared generic code with catch
5738                                  * clauses containing type variables
5739                                  * the exception handling code has to
5740                                  * be able to get to the rgctx.
5741                                  * Therefore we have to make sure that
5742                                  * the vtable/mrgctx argument (for
5743                                  * static or generic methods) or the
5744                                  * "this" argument (for non-static
5745                                  * methods) are live.
5746                                  */
5747                                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5748                                                 mini_method_get_context (method)->method_inst ||
5749                                                 method->klass->valuetype) {
5750                                         mono_get_vtable_var (cfg);
5751                                 } else {
5752                                         MonoInst *dummy_use;
5753
5754                                         EMIT_NEW_DUMMY_USE (cfg, dummy_use, arg_array [0]);
5755                                 }
5756                         }
5757                 }
5758         } else {
5759                 arg_array = (MonoInst **) alloca (sizeof (MonoInst *) * num_args);
5760                 cfg->cbb = start_bblock;
5761                 cfg->args = arg_array;
5762                 mono_save_args (cfg, sig, inline_args);
5763         }
5764
5765         /* FIRST CODE BLOCK */
5766         NEW_BBLOCK (cfg, bblock);
5767         bblock->cil_code = ip;
5768         cfg->cbb = bblock;
5769         cfg->ip = ip;
5770
5771         ADD_BBLOCK (cfg, bblock);
5772
5773         if (cfg->method == method) {
5774                 breakpoint_id = mono_debugger_method_has_breakpoint (method);
5775                 if (breakpoint_id && (mono_debug_format != MONO_DEBUG_FORMAT_DEBUGGER)) {
5776                         MONO_INST_NEW (cfg, ins, OP_BREAK);
5777                         MONO_ADD_INS (bblock, ins);
5778                 }
5779         }
5780
5781         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
5782                 secman = mono_security_manager_get_methods ();
5783
5784         security = (secman && mono_method_has_declsec (method));
5785         /* at this point having security doesn't mean we have any code to generate */
5786         if (security && (cfg->method == method)) {
5787                 /* Only Demand, NonCasDemand and DemandChoice requires code generation.
5788                  * And we do not want to enter the next section (with allocation) if we
5789                  * have nothing to generate */
5790                 security = mono_declsec_get_demands (method, &actions);
5791         }
5792
5793         /* we must Demand SecurityPermission.Unmanaged before P/Invoking */
5794         pinvoke = (secman && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE));
5795         if (pinvoke) {
5796                 MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5797                 if (wrapped && (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
5798                         MonoCustomAttrInfo* custom = mono_custom_attrs_from_method (wrapped);
5799
5800                         /* unless the method or it's class has the [SuppressUnmanagedCodeSecurity] attribute */
5801                         if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5802                                 pinvoke = FALSE;
5803                         }
5804                         if (custom)
5805                                 mono_custom_attrs_free (custom);
5806
5807                         if (pinvoke) {
5808                                 custom = mono_custom_attrs_from_class (wrapped->klass);
5809                                 if (custom && mono_custom_attrs_has_attr (custom, secman->suppressunmanagedcodesecurity)) {
5810                                         pinvoke = FALSE;
5811                                 }
5812                                 if (custom)
5813                                         mono_custom_attrs_free (custom);
5814                         }
5815                 } else {
5816                         /* not a P/Invoke after all */
5817                         pinvoke = FALSE;
5818                 }
5819         }
5820         
5821         if ((init_locals || (cfg->method == method && (cfg->opt & MONO_OPT_SHARED))) || cfg->compile_aot || security || pinvoke) {
5822                 /* we use a separate basic block for the initialization code */
5823                 NEW_BBLOCK (cfg, init_localsbb);
5824                 cfg->bb_init = init_localsbb;
5825                 init_localsbb->real_offset = cfg->real_offset;
5826                 start_bblock->next_bb = init_localsbb;
5827                 init_localsbb->next_bb = bblock;
5828                 link_bblock (cfg, start_bblock, init_localsbb);
5829                 link_bblock (cfg, init_localsbb, bblock);
5830                 
5831                 cfg->cbb = init_localsbb;
5832         } else {
5833                 start_bblock->next_bb = bblock;
5834                 link_bblock (cfg, start_bblock, bblock);
5835         }
5836
5837         /* at this point we know, if security is TRUE, that some code needs to be generated */
5838         if (security && (cfg->method == method)) {
5839                 MonoInst *args [2];
5840
5841                 mono_jit_stats.cas_demand_generation++;
5842
5843                 if (actions.demand.blob) {
5844                         /* Add code for SecurityAction.Demand */
5845                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demand);
5846                         EMIT_NEW_ICONST (cfg, args [1], actions.demand.size);
5847                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5848                         mono_emit_method_call (cfg, secman->demand, args, NULL);
5849                 }
5850                 if (actions.noncasdemand.blob) {
5851                         /* CLR 1.x uses a .noncasdemand (but 2.x doesn't) */
5852                         /* For Mono we re-route non-CAS Demand to Demand (as the managed code must deal with it anyway) */
5853                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.noncasdemand);
5854                         EMIT_NEW_ICONST (cfg, args [1], actions.noncasdemand.size);
5855                         /* Calls static void SecurityManager.InternalDemand (byte* permissions, int size); */
5856                         mono_emit_method_call (cfg, secman->demand, args, NULL);
5857                 }
5858                 if (actions.demandchoice.blob) {
5859                         /* New in 2.0, Demand must succeed for one of the permissions (i.e. not all) */
5860                         EMIT_NEW_DECLSECCONST (cfg, args[0], image, actions.demandchoice);
5861                         EMIT_NEW_ICONST (cfg, args [1], actions.demandchoice.size);
5862                         /* Calls static void SecurityManager.InternalDemandChoice (byte* permissions, int size); */
5863                         mono_emit_method_call (cfg, secman->demandchoice, args, NULL);
5864                 }
5865         }
5866
5867         /* we must Demand SecurityPermission.Unmanaged before p/invoking */
5868         if (pinvoke) {
5869                 mono_emit_method_call (cfg, secman->demandunmanaged, NULL, NULL);
5870         }
5871
5872         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
5873                 /* check if this is native code, e.g. an icall or a p/invoke */
5874                 if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) {
5875                         MonoMethod *wrapped = mono_marshal_method_from_wrapper (method);
5876                         if (wrapped) {
5877                                 gboolean pinvk = (wrapped->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL);
5878                                 gboolean icall = (wrapped->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL);
5879
5880                                 /* if this ia a native call then it can only be JITted from platform code */
5881                                 if ((icall || pinvk) && method->klass && method->klass->image) {
5882                                         if (!mono_security_core_clr_is_platform_image (method->klass->image)) {
5883                                                 MonoException *ex = icall ? mono_get_exception_security () : 
5884                                                         mono_get_exception_method_access ();
5885                                                 emit_throw_exception (cfg, ex);
5886                                         }
5887                                 }
5888                         }
5889                 }
5890         }
5891
5892         if (header->code_size == 0)
5893                 UNVERIFIED;
5894
5895         if (get_basic_blocks (cfg, header, cfg->real_offset, ip, end, &err_pos)) {
5896                 ip = err_pos;
5897                 UNVERIFIED;
5898         }
5899
5900         if (cfg->method == method)
5901                 mono_debug_init_method (cfg, bblock, breakpoint_id);
5902
5903         for (n = 0; n < header->num_locals; ++n) {
5904                 if (header->locals [n]->type == MONO_TYPE_VOID && !header->locals [n]->byref)
5905                         UNVERIFIED;
5906         }
5907         class_inits = NULL;
5908
5909         /* We force the vtable variable here for all shared methods
5910            for the possibility that they might show up in a stack
5911            trace where their exact instantiation is needed. */
5912         if (cfg->generic_sharing_context && method == cfg->method) {
5913                 if ((method->flags & METHOD_ATTRIBUTE_STATIC) ||
5914                                 mini_method_get_context (method)->method_inst ||
5915                                 method->klass->valuetype) {
5916                         mono_get_vtable_var (cfg);
5917                 } else {
5918                         /* FIXME: Is there a better way to do this?
5919                            We need the variable live for the duration
5920                            of the whole method. */
5921                         cfg->args [0]->flags |= MONO_INST_INDIRECT;
5922                 }
5923         }
5924
5925         /* add a check for this != NULL to inlined methods */
5926         if (is_virtual_call) {
5927                 MonoInst *arg_ins;
5928
5929                 NEW_ARGLOAD (cfg, arg_ins, 0);
5930                 MONO_ADD_INS (cfg->cbb, arg_ins);
5931                 MONO_EMIT_NEW_CHECK_THIS (cfg, arg_ins->dreg);
5932         }
5933
5934         skip_dead_blocks = !dont_verify;
5935         if (skip_dead_blocks) {
5936                 original_bb = bb = mono_basic_block_split (method, &error);
5937                 if (!mono_error_ok (&error)) {
5938                         mono_error_cleanup (&error);
5939                         UNVERIFIED;
5940                 }
5941                 g_assert (bb);
5942         }
5943
5944         /* we use a spare stack slot in SWITCH and NEWOBJ and others */
5945         stack_start = sp = mono_mempool_alloc0 (cfg->mempool, sizeof (MonoInst*) * (header->max_stack + 1));
5946
5947         ins_flag = 0;
5948         start_new_bblock = 0;
5949         cfg->cbb = bblock;
5950         while (ip < end) {
5951                 if (cfg->method == method)
5952                         cfg->real_offset = ip - header->code;
5953                 else
5954                         cfg->real_offset = inline_offset;
5955                 cfg->ip = ip;
5956
5957                 context_used = 0;
5958                 
5959                 if (start_new_bblock) {
5960                         bblock->cil_length = ip - bblock->cil_code;
5961                         if (start_new_bblock == 2) {
5962                                 g_assert (ip == tblock->cil_code);
5963                         } else {
5964                                 GET_BBLOCK (cfg, tblock, ip);
5965                         }
5966                         bblock->next_bb = tblock;
5967                         bblock = tblock;
5968                         cfg->cbb = bblock;
5969                         start_new_bblock = 0;
5970                         for (i = 0; i < bblock->in_scount; ++i) {
5971                                 if (cfg->verbose_level > 3)
5972                                         printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
5973                                 EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5974                                 *sp++ = ins;
5975                         }
5976                         if (class_inits)
5977                                 g_slist_free (class_inits);
5978                         class_inits = NULL;
5979                 } else {
5980                         if ((tblock = cfg->cil_offset_to_bb [ip - cfg->cil_start]) && (tblock != bblock)) {
5981                                 link_bblock (cfg, bblock, tblock);
5982                                 if (sp != stack_start) {
5983                                         handle_stack_args (cfg, stack_start, sp - stack_start);
5984                                         sp = stack_start;
5985                                         CHECK_UNVERIFIABLE (cfg);
5986                                 }
5987                                 bblock->next_bb = tblock;
5988                                 bblock = tblock;
5989                                 cfg->cbb = bblock;
5990                                 for (i = 0; i < bblock->in_scount; ++i) {
5991                                         if (cfg->verbose_level > 3)
5992                                                 printf ("loading %d from temp %d\n", i, (int)bblock->in_stack [i]->inst_c0);                                            
5993                                         EMIT_NEW_TEMPLOAD (cfg, ins, bblock->in_stack [i]->inst_c0);
5994                                         *sp++ = ins;
5995                                 }
5996                                 g_slist_free (class_inits);
5997                                 class_inits = NULL;
5998                         }
5999                 }
6000
6001                 if (skip_dead_blocks) {
6002                         int ip_offset = ip - header->code;
6003
6004                         if (ip_offset == bb->end)
6005                                 bb = bb->next;
6006
6007                         if (bb->dead) {
6008                                 int op_size = mono_opcode_size (ip, end);
6009                                 g_assert (op_size > 0); /*The BB formation pass must catch all bad ops*/
6010
6011                                 if (cfg->verbose_level > 3) printf ("SKIPPING DEAD OP at %x\n", ip_offset);
6012
6013                                 if (ip_offset + op_size == bb->end) {
6014                                         MONO_INST_NEW (cfg, ins, OP_NOP);
6015                                         MONO_ADD_INS (bblock, ins);
6016                                         start_new_bblock = 1;
6017                                 }
6018
6019                                 ip += op_size;
6020                                 continue;
6021                         }
6022                 }
6023                 /*
6024                  * Sequence points are points where the debugger can place a breakpoint.
6025                  * Currently, we generate these automatically at points where the IL
6026                  * stack is empty.
6027                  */
6028                 if (seq_points && sp == stack_start) {
6029                         NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
6030                         MONO_ADD_INS (cfg->cbb, ins);
6031                 }
6032
6033                 bblock->real_offset = cfg->real_offset;
6034
6035                 if ((cfg->method == method) && cfg->coverage_info) {
6036                         guint32 cil_offset = ip - header->code;
6037                         cfg->coverage_info->data [cil_offset].cil_code = ip;
6038
6039                         /* TODO: Use an increment here */
6040 #if defined(TARGET_X86)
6041                         MONO_INST_NEW (cfg, ins, OP_STORE_MEM_IMM);
6042                         ins->inst_p0 = &(cfg->coverage_info->data [cil_offset].count);
6043                         ins->inst_imm = 1;
6044                         MONO_ADD_INS (cfg->cbb, ins);
6045 #else
6046                         EMIT_NEW_PCONST (cfg, ins, &(cfg->coverage_info->data [cil_offset].count));
6047                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, ins->dreg, 0, 1);
6048 #endif
6049                 }
6050
6051                 if (cfg->verbose_level > 3)
6052                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
6053
6054                 switch (*ip) {
6055                 case CEE_NOP:
6056                         if (cfg->keep_cil_nops)
6057                                 MONO_INST_NEW (cfg, ins, OP_HARD_NOP);
6058                         else
6059                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6060                         ip++;
6061                         MONO_ADD_INS (bblock, ins);
6062                         break;
6063                 case CEE_BREAK:
6064                         if (should_insert_brekpoint (cfg->method))
6065                                 MONO_INST_NEW (cfg, ins, OP_BREAK);
6066                         else
6067                                 MONO_INST_NEW (cfg, ins, OP_NOP);
6068                         ip++;
6069                         MONO_ADD_INS (bblock, ins);
6070                         break;
6071                 case CEE_LDARG_0:
6072                 case CEE_LDARG_1:
6073                 case CEE_LDARG_2:
6074                 case CEE_LDARG_3:
6075                         CHECK_STACK_OVF (1);
6076                         n = (*ip)-CEE_LDARG_0;
6077                         CHECK_ARG (n);
6078                         EMIT_NEW_ARGLOAD (cfg, ins, n);
6079                         ip++;
6080                         *sp++ = ins;
6081                         break;
6082                 case CEE_LDLOC_0:
6083                 case CEE_LDLOC_1:
6084                 case CEE_LDLOC_2:
6085                 case CEE_LDLOC_3:
6086                         CHECK_STACK_OVF (1);
6087                         n = (*ip)-CEE_LDLOC_0;
6088                         CHECK_LOCAL (n);
6089                         EMIT_NEW_LOCLOAD (cfg, ins, n);
6090                         ip++;
6091                         *sp++ = ins;
6092                         break;
6093                 case CEE_STLOC_0:
6094                 case CEE_STLOC_1:
6095                 case CEE_STLOC_2:
6096                 case CEE_STLOC_3: {
6097                         CHECK_STACK (1);
6098                         n = (*ip)-CEE_STLOC_0;
6099                         CHECK_LOCAL (n);
6100                         --sp;
6101                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
6102                                 UNVERIFIED;
6103                         emit_stloc_ir (cfg, sp, header, n);
6104                         ++ip;
6105                         inline_costs += 1;
6106                         break;
6107                         }
6108                 case CEE_LDARG_S:
6109                         CHECK_OPSIZE (2);
6110                         CHECK_STACK_OVF (1);
6111                         n = ip [1];
6112                         CHECK_ARG (n);
6113                         EMIT_NEW_ARGLOAD (cfg, ins, n);
6114                         *sp++ = ins;
6115                         ip += 2;
6116                         break;
6117                 case CEE_LDARGA_S:
6118                         CHECK_OPSIZE (2);
6119                         CHECK_STACK_OVF (1);
6120                         n = ip [1];
6121                         CHECK_ARG (n);
6122                         NEW_ARGLOADA (cfg, ins, n);
6123                         MONO_ADD_INS (cfg->cbb, ins);
6124                         *sp++ = ins;
6125                         ip += 2;
6126                         break;
6127                 case CEE_STARG_S:
6128                         CHECK_OPSIZE (2);
6129                         CHECK_STACK (1);
6130                         --sp;
6131                         n = ip [1];
6132                         CHECK_ARG (n);
6133                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [ip [1]], *sp))
6134                                 UNVERIFIED;
6135                         EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
6136                         ip += 2;
6137                         break;
6138                 case CEE_LDLOC_S:
6139                         CHECK_OPSIZE (2);
6140                         CHECK_STACK_OVF (1);
6141                         n = ip [1];
6142                         CHECK_LOCAL (n);
6143                         EMIT_NEW_LOCLOAD (cfg, ins, n);
6144                         *sp++ = ins;
6145                         ip += 2;
6146                         break;
6147                 case CEE_LDLOCA_S: {
6148                         unsigned char *tmp_ip;
6149                         CHECK_OPSIZE (2);
6150                         CHECK_STACK_OVF (1);
6151                         CHECK_LOCAL (ip [1]);
6152
6153                         if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 1))) {
6154                                 ip = tmp_ip;
6155                                 inline_costs += 1;
6156                                 break;
6157                         }
6158
6159                         EMIT_NEW_LOCLOADA (cfg, ins, ip [1]);
6160                         *sp++ = ins;
6161                         ip += 2;
6162                         break;
6163                 }
6164                 case CEE_STLOC_S:
6165                         CHECK_OPSIZE (2);
6166                         CHECK_STACK (1);
6167                         --sp;
6168                         CHECK_LOCAL (ip [1]);
6169                         if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [ip [1]], *sp))
6170                                 UNVERIFIED;
6171                         emit_stloc_ir (cfg, sp, header, ip [1]);
6172                         ip += 2;
6173                         inline_costs += 1;
6174                         break;
6175                 case CEE_LDNULL:
6176                         CHECK_STACK_OVF (1);
6177                         EMIT_NEW_PCONST (cfg, ins, NULL);
6178                         ins->type = STACK_OBJ;
6179                         ++ip;
6180                         *sp++ = ins;
6181                         break;
6182                 case CEE_LDC_I4_M1:
6183                         CHECK_STACK_OVF (1);
6184                         EMIT_NEW_ICONST (cfg, ins, -1);
6185                         ++ip;
6186                         *sp++ = ins;
6187                         break;
6188                 case CEE_LDC_I4_0:
6189                 case CEE_LDC_I4_1:
6190                 case CEE_LDC_I4_2:
6191                 case CEE_LDC_I4_3:
6192                 case CEE_LDC_I4_4:
6193                 case CEE_LDC_I4_5:
6194                 case CEE_LDC_I4_6:
6195                 case CEE_LDC_I4_7:
6196                 case CEE_LDC_I4_8:
6197                         CHECK_STACK_OVF (1);
6198                         EMIT_NEW_ICONST (cfg, ins, (*ip) - CEE_LDC_I4_0);
6199                         ++ip;
6200                         *sp++ = ins;
6201                         break;
6202                 case CEE_LDC_I4_S:
6203                         CHECK_OPSIZE (2);
6204                         CHECK_STACK_OVF (1);
6205                         ++ip;
6206                         EMIT_NEW_ICONST (cfg, ins, *((signed char*)ip));
6207                         ++ip;
6208                         *sp++ = ins;
6209                         break;
6210                 case CEE_LDC_I4:
6211                         CHECK_OPSIZE (5);
6212                         CHECK_STACK_OVF (1);
6213                         EMIT_NEW_ICONST (cfg, ins, (gint32)read32 (ip + 1));
6214                         ip += 5;
6215                         *sp++ = ins;
6216                         break;
6217                 case CEE_LDC_I8:
6218                         CHECK_OPSIZE (9);
6219                         CHECK_STACK_OVF (1);
6220                         MONO_INST_NEW (cfg, ins, OP_I8CONST);
6221                         ins->type = STACK_I8;
6222                         ins->dreg = alloc_dreg (cfg, STACK_I8);
6223                         ++ip;
6224                         ins->inst_l = (gint64)read64 (ip);
6225                         MONO_ADD_INS (bblock, ins);
6226                         ip += 8;
6227                         *sp++ = ins;
6228                         break;
6229                 case CEE_LDC_R4: {
6230                         float *f;
6231                         gboolean use_aotconst = FALSE;
6232
6233 #ifdef TARGET_POWERPC
6234                         /* FIXME: Clean this up */
6235                         if (cfg->compile_aot)
6236                                 use_aotconst = TRUE;
6237 #endif
6238
6239                         /* FIXME: we should really allocate this only late in the compilation process */
6240                         f = mono_domain_alloc (cfg->domain, sizeof (float));
6241                         CHECK_OPSIZE (5);
6242                         CHECK_STACK_OVF (1);
6243
6244                         if (use_aotconst) {
6245                                 MonoInst *cons;
6246                                 int dreg;
6247
6248                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R4, f);
6249
6250                                 dreg = alloc_freg (cfg);
6251                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR4_MEMBASE, dreg, cons->dreg, 0);
6252                                 ins->type = STACK_R8;
6253                         } else {
6254                                 MONO_INST_NEW (cfg, ins, OP_R4CONST);
6255                                 ins->type = STACK_R8;
6256                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
6257                                 ins->inst_p0 = f;
6258                                 MONO_ADD_INS (bblock, ins);
6259                         }
6260                         ++ip;
6261                         readr4 (ip, f);
6262                         ip += 4;
6263                         *sp++ = ins;                    
6264                         break;
6265                 }
6266                 case CEE_LDC_R8: {
6267                         double *d;
6268                         gboolean use_aotconst = FALSE;
6269
6270 #ifdef TARGET_POWERPC
6271                         /* FIXME: Clean this up */
6272                         if (cfg->compile_aot)
6273                                 use_aotconst = TRUE;
6274 #endif
6275
6276                         /* FIXME: we should really allocate this only late in the compilation process */
6277                         d = mono_domain_alloc (cfg->domain, sizeof (double));
6278                         CHECK_OPSIZE (9);
6279                         CHECK_STACK_OVF (1);
6280
6281                         if (use_aotconst) {
6282                                 MonoInst *cons;
6283                                 int dreg;
6284
6285                                 EMIT_NEW_AOTCONST (cfg, cons, MONO_PATCH_INFO_R8, d);
6286
6287                                 dreg = alloc_freg (cfg);
6288                                 EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADR8_MEMBASE, dreg, cons->dreg, 0);
6289                                 ins->type = STACK_R8;
6290                         } else {
6291                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
6292                                 ins->type = STACK_R8;
6293                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
6294                                 ins->inst_p0 = d;
6295                                 MONO_ADD_INS (bblock, ins);
6296                         }
6297                         ++ip;
6298                         readr8 (ip, d);
6299                         ip += 8;
6300                         *sp++ = ins;
6301                         break;
6302                 }
6303                 case CEE_DUP: {
6304                         MonoInst *temp, *store;
6305                         CHECK_STACK (1);
6306                         CHECK_STACK_OVF (1);
6307                         sp--;
6308                         ins = *sp;
6309
6310                         temp = mono_compile_create_var (cfg, type_from_stack_type (ins), OP_LOCAL);
6311                         EMIT_NEW_TEMPSTORE (cfg, store, temp->inst_c0, ins);
6312
6313                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6314                         *sp++ = ins;
6315
6316                         EMIT_NEW_TEMPLOAD (cfg, ins, temp->inst_c0);
6317                         *sp++ = ins;
6318
6319                         ++ip;
6320                         inline_costs += 2;
6321                         break;
6322                 }
6323                 case CEE_POP:
6324                         CHECK_STACK (1);
6325                         ip++;
6326                         --sp;
6327
6328 #ifdef TARGET_X86
6329                         if (sp [0]->type == STACK_R8)
6330                                 /* we need to pop the value from the x86 FP stack */
6331                                 MONO_EMIT_NEW_UNALU (cfg, OP_X86_FPOP, -1, sp [0]->dreg);
6332 #endif
6333                         break;
6334                 case CEE_JMP: {
6335                         MonoCallInst *call;
6336
6337                         INLINE_FAILURE;
6338
6339                         CHECK_OPSIZE (5);
6340                         if (stack_start != sp)
6341                                 UNVERIFIED;
6342                         token = read32 (ip + 1);
6343                         /* FIXME: check the signature matches */
6344                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6345
6346                         if (!cmethod || mono_loader_get_last_error ())
6347                                 LOAD_ERROR;
6348  
6349                         if (cfg->generic_sharing_context && mono_method_check_context_used (cmethod))
6350                                 GENERIC_SHARING_FAILURE (CEE_JMP);
6351
6352                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS)
6353                                 CHECK_CFG_EXCEPTION;
6354
6355 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6356                         {
6357                                 MonoMethodSignature *fsig = mono_method_signature (cmethod);
6358                                 int i, n;
6359
6360                                 /* Handle tail calls similarly to calls */
6361                                 n = fsig->param_count + fsig->hasthis;
6362
6363                                 MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
6364                                 call->method = cmethod;
6365                                 call->tail_call = TRUE;
6366                                 call->signature = mono_method_signature (cmethod);
6367                                 call->args = mono_mempool_alloc (cfg->mempool, sizeof (MonoInst*) * n);
6368                                 call->inst.inst_p0 = cmethod;
6369                                 for (i = 0; i < n; ++i)
6370                                         EMIT_NEW_ARGLOAD (cfg, call->args [i], i);
6371
6372                                 mono_arch_emit_call (cfg, call);
6373                                 MONO_ADD_INS (bblock, (MonoInst*)call);
6374                         }
6375 #else
6376                         for (i = 0; i < num_args; ++i)
6377                                 /* Prevent arguments from being optimized away */
6378                                 arg_array [i]->flags |= MONO_INST_VOLATILE;
6379
6380                         MONO_INST_NEW_CALL (cfg, call, OP_JMP);
6381                         ins = (MonoInst*)call;
6382                         ins->inst_p0 = cmethod;
6383                         MONO_ADD_INS (bblock, ins);
6384 #endif
6385
6386                         ip += 5;
6387                         start_new_bblock = 1;
6388                         break;
6389                 }
6390                 case CEE_CALLI:
6391                 case CEE_CALL:
6392                 case CEE_CALLVIRT: {
6393                         MonoInst *addr = NULL;
6394                         MonoMethodSignature *fsig = NULL;
6395                         int array_rank = 0;
6396                         int virtual = *ip == CEE_CALLVIRT;
6397                         int calli = *ip == CEE_CALLI;
6398                         gboolean pass_imt_from_rgctx = FALSE;
6399                         MonoInst *imt_arg = NULL;
6400                         gboolean pass_vtable = FALSE;
6401                         gboolean pass_mrgctx = FALSE;
6402                         MonoInst *vtable_arg = NULL;
6403                         gboolean check_this = FALSE;
6404                         gboolean supported_tail_call = FALSE;
6405
6406                         CHECK_OPSIZE (5);
6407                         token = read32 (ip + 1);
6408
6409                         if (calli) {
6410                                 cmethod = NULL;
6411                                 CHECK_STACK (1);
6412                                 --sp;
6413                                 addr = *sp;
6414                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
6415                                         fsig = (MonoMethodSignature *)mono_method_get_wrapper_data (method, token);
6416                                 else
6417                                         fsig = mono_metadata_parse_signature (image, token);
6418
6419                                 n = fsig->param_count + fsig->hasthis;
6420
6421                                 if (method->dynamic && fsig->pinvoke) {
6422                                         MonoInst *args [3];
6423
6424                                         /*
6425                                          * This is a call through a function pointer using a pinvoke
6426                                          * signature. Have to create a wrapper and call that instead.
6427                                          * FIXME: This is very slow, need to create a wrapper at JIT time
6428                                          * instead based on the signature.
6429                                          */
6430                                         EMIT_NEW_IMAGECONST (cfg, args [0], method->klass->image);
6431                                         EMIT_NEW_PCONST (cfg, args [1], fsig);
6432                                         args [2] = addr;
6433                                         addr = mono_emit_jit_icall (cfg, mono_get_native_calli_wrapper, args);
6434                                 }
6435                         } else {
6436                                 MonoMethod *cil_method;
6437                                 
6438                                 if (method->wrapper_type != MONO_WRAPPER_NONE) {
6439                                         cmethod =  (MonoMethod *)mono_method_get_wrapper_data (method, token);
6440                                         cil_method = cmethod;
6441                                 } else if (constrained_call) {
6442                                         if ((constrained_call->byval_arg.type == MONO_TYPE_VAR || constrained_call->byval_arg.type == MONO_TYPE_MVAR) && cfg->generic_sharing_context) {
6443                                                 /* 
6444                                                  * This is needed since get_method_constrained can't find 
6445                                                  * the method in klass representing a type var.
6446                                                  * The type var is guaranteed to be a reference type in this
6447                                                  * case.
6448                                                  */
6449                                                 cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6450                                                 cil_method = cmethod;
6451                                                 g_assert (!cmethod->klass->valuetype);
6452                                         } else {
6453                                                 cmethod = mono_get_method_constrained (image, token, constrained_call, generic_context, &cil_method);
6454                                         }
6455                                 } else {
6456                                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
6457                                         cil_method = cmethod;
6458                                 }
6459
6460                                 if (!cmethod || mono_loader_get_last_error ())
6461                                         LOAD_ERROR;
6462                                 if (!dont_verify && !cfg->skip_visibility) {
6463                                         MonoMethod *target_method = cil_method;
6464                                         if (method->is_inflated) {
6465                                                 target_method = mini_get_method_allow_open (method, token, NULL, &(mono_method_get_generic_container (method_definition)->context));
6466                                         }
6467                                         if (!mono_method_can_access_method (method_definition, target_method) &&
6468                                                 !mono_method_can_access_method (method, cil_method))
6469                                                 METHOD_ACCESS_FAILURE;
6470                                 }
6471
6472                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
6473                                         ensure_method_is_allowed_to_call_method (cfg, method, cil_method, bblock, ip);
6474
6475                                 if (!virtual && (cmethod->flags & METHOD_ATTRIBUTE_ABSTRACT))
6476                                         /* MS.NET seems to silently convert this to a callvirt */
6477                                         virtual = 1;
6478
6479                                 {
6480                                         /*
6481                                          * MS.NET accepts non virtual calls to virtual final methods of transparent proxy classes and
6482                                          * converts to a callvirt.
6483                                          *
6484                                          * tests/bug-515884.il is an example of this behavior
6485                                          */
6486                                         const int test_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL | METHOD_ATTRIBUTE_STATIC;
6487                                         const int expected_flags = METHOD_ATTRIBUTE_VIRTUAL | METHOD_ATTRIBUTE_FINAL;
6488                                         if (!virtual && cmethod->klass->marshalbyref && (cmethod->flags & test_flags) == expected_flags && cfg->method->wrapper_type == MONO_WRAPPER_NONE)
6489                                                 virtual = 1;
6490                                 }
6491
6492                                 if (!cmethod->klass->inited)
6493                                         if (!mono_class_init (cmethod->klass))
6494                                                 LOAD_ERROR;
6495
6496                                 if (cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL &&
6497                                     mini_class_is_system_array (cmethod->klass)) {
6498                                         array_rank = cmethod->klass->rank;
6499                                         fsig = mono_method_signature (cmethod);
6500                                 } else {
6501                                         fsig = mono_method_signature (cmethod);
6502
6503                                         if (!fsig)
6504                                                 LOAD_ERROR;
6505
6506                                         if (fsig->pinvoke) {
6507                                                 MonoMethod *wrapper = mono_marshal_get_native_wrapper (cmethod,
6508                                                         check_for_pending_exc, FALSE);
6509                                                 fsig = mono_method_signature (wrapper);
6510                                         } else if (constrained_call) {
6511                                                 fsig = mono_method_signature (cmethod);
6512                                         } else {
6513                                                 fsig = mono_method_get_signature_full (cmethod, image, token, generic_context);
6514                                         }
6515                                 }
6516
6517                                 mono_save_token_info (cfg, image, token, cil_method);
6518
6519                                 n = fsig->param_count + fsig->hasthis;
6520
6521                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
6522                                         if (check_linkdemand (cfg, method, cmethod))
6523                                                 INLINE_FAILURE;
6524                                         CHECK_CFG_EXCEPTION;
6525                                 }
6526
6527                                 if (cmethod->string_ctor && method->wrapper_type != MONO_WRAPPER_RUNTIME_INVOKE)
6528                                         g_assert_not_reached ();
6529                         }
6530
6531                         if (!cfg->generic_sharing_context && cmethod && cmethod->klass->generic_container)
6532                                 UNVERIFIED;
6533
6534                         if (!cfg->generic_sharing_context && cmethod)
6535                                 g_assert (!mono_method_check_context_used (cmethod));
6536
6537                         CHECK_STACK (n);
6538
6539                         //g_assert (!virtual || fsig->hasthis);
6540
6541                         sp -= n;
6542
6543                         if (constrained_call) {
6544                                 /*
6545                                  * We have the `constrained.' prefix opcode.
6546                                  */
6547                                 if (constrained_call->valuetype && !cmethod->klass->valuetype) {
6548                                         /*
6549                                          * The type parameter is instantiated as a valuetype,
6550                                          * but that type doesn't override the method we're
6551                                          * calling, so we need to box `this'.
6552                                          */
6553                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &constrained_call->byval_arg, sp [0]->dreg, 0);
6554                                         ins->klass = constrained_call;
6555                                         sp [0] = handle_box (cfg, ins, constrained_call, mono_class_check_context_used (constrained_call));
6556                                         CHECK_CFG_EXCEPTION;
6557                                 } else if (!constrained_call->valuetype) {
6558                                         int dreg = alloc_preg (cfg);
6559
6560                                         /*
6561                                          * The type parameter is instantiated as a reference
6562                                          * type.  We have a managed pointer on the stack, so
6563                                          * we need to dereference it here.
6564                                          */
6565                                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, sp [0]->dreg, 0);
6566                                         ins->type = STACK_OBJ;
6567                                         sp [0] = ins;
6568                                 } else if (cmethod->klass->valuetype)
6569                                         virtual = 0;
6570                                 constrained_call = NULL;
6571                         }
6572
6573                         if (*ip != CEE_CALLI && check_call_signature (cfg, fsig, sp))
6574                                 UNVERIFIED;
6575
6576                         /* 
6577                          * If the callee is a shared method, then its static cctor
6578                          * might not get called after the call was patched.
6579                          */
6580                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable_impl (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
6581                                 emit_generic_class_init (cfg, cmethod->klass);
6582                                 CHECK_TYPELOAD (cmethod->klass);
6583                         }
6584
6585                         if (cmethod && ((cmethod->flags & METHOD_ATTRIBUTE_STATIC) || cmethod->klass->valuetype) &&
6586                                         (cmethod->klass->generic_class || cmethod->klass->generic_container)) {
6587                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6588                                 MonoGenericContext *context = mini_class_get_context (cmethod->klass);
6589                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6590
6591                                 /*
6592                                  * Pass vtable iff target method might
6593                                  * be shared, which means that sharing
6594                                  * is enabled for its class and its
6595                                  * context is sharable (and it's not a
6596                                  * generic method).
6597                                  */
6598                                 if (sharing_enabled && context_sharable &&
6599                                         !(mini_method_get_context (cmethod) && mini_method_get_context (cmethod)->method_inst))
6600                                         pass_vtable = TRUE;
6601                         }
6602
6603                         if (cmethod && mini_method_get_context (cmethod) &&
6604                                         mini_method_get_context (cmethod)->method_inst) {
6605                                 gboolean sharing_enabled = mono_class_generic_sharing_enabled (cmethod->klass);
6606                                 MonoGenericContext *context = mini_method_get_context (cmethod);
6607                                 gboolean context_sharable = mono_generic_context_is_sharable (context, TRUE);
6608
6609                                 g_assert (!pass_vtable);
6610
6611                                 if (sharing_enabled && context_sharable)
6612                                         pass_mrgctx = TRUE;
6613                         }
6614
6615                         if (cfg->generic_sharing_context && cmethod) {
6616                                 MonoGenericContext *cmethod_context = mono_method_get_context (cmethod);
6617
6618                                 context_used = mono_method_check_context_used (cmethod);
6619
6620                                 if (context_used && (cmethod->klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
6621                                         /* Generic method interface
6622                                            calls are resolved via a
6623                                            helper function and don't
6624                                            need an imt. */
6625                                         if (!cmethod_context || !cmethod_context->method_inst)
6626                                                 pass_imt_from_rgctx = TRUE;
6627                                 }
6628
6629                                 /*
6630                                  * If a shared method calls another
6631                                  * shared method then the caller must
6632                                  * have a generic sharing context
6633                                  * because the magic trampoline
6634                                  * requires it.  FIXME: We shouldn't
6635                                  * have to force the vtable/mrgctx
6636                                  * variable here.  Instead there
6637                                  * should be a flag in the cfg to
6638                                  * request a generic sharing context.
6639                                  */
6640                                 if (context_used &&
6641                                                 ((method->flags & METHOD_ATTRIBUTE_STATIC) || method->klass->valuetype))
6642                                         mono_get_vtable_var (cfg);
6643                         }
6644
6645                         if (pass_vtable) {
6646                                 if (context_used) {
6647                                         vtable_arg = emit_get_rgctx_klass (cfg, context_used, cmethod->klass, MONO_RGCTX_INFO_VTABLE);
6648                                 } else {
6649                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
6650
6651                                         CHECK_TYPELOAD (cmethod->klass);
6652                                         EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
6653                                 }
6654                         }
6655
6656                         if (pass_mrgctx) {
6657                                 g_assert (!vtable_arg);
6658
6659                                 if (!cfg->compile_aot) {
6660                                         /* 
6661                                          * emit_get_rgctx_method () calls mono_class_vtable () so check 
6662                                          * for type load errors before.
6663                                          */
6664                                         mono_class_setup_vtable (cmethod->klass);
6665                                         CHECK_TYPELOAD (cmethod->klass);
6666                                 }
6667
6668                                 vtable_arg = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
6669
6670                                 /* !marshalbyref is needed to properly handle generic methods + remoting */
6671                                 if ((!(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) ||
6672                                          MONO_METHOD_IS_FINAL (cmethod)) &&
6673                                         !cmethod->klass->marshalbyref) {
6674                                         if (virtual)
6675                                                 check_this = TRUE;
6676                                         virtual = 0;
6677                                 }
6678                         }
6679
6680                         if (pass_imt_from_rgctx) {
6681                                 g_assert (!pass_vtable);
6682                                 g_assert (cmethod);
6683
6684                                 imt_arg = emit_get_rgctx_method (cfg, context_used,
6685                                         cmethod, MONO_RGCTX_INFO_METHOD);
6686                         }
6687
6688                         if (check_this)
6689                                 MONO_EMIT_NEW_CHECK_THIS (cfg, sp [0]->dreg);
6690
6691                         /* Calling virtual generic methods */
6692                         if (cmethod && virtual && 
6693                             (cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) && 
6694                             !(MONO_METHOD_IS_FINAL (cmethod) && 
6695                               cmethod->wrapper_type != MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK) &&
6696                             mono_method_signature (cmethod)->generic_param_count) {
6697                                 MonoInst *this_temp, *this_arg_temp, *store;
6698                                 MonoInst *iargs [4];
6699
6700                                 g_assert (mono_method_signature (cmethod)->is_inflated);
6701
6702                                 /* Prevent inlining of methods that contain indirect calls */
6703                                 INLINE_FAILURE;
6704
6705 #if MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK && defined(MONO_ARCH_GSHARED_SUPPORTED)
6706                                 if (cmethod->wrapper_type == MONO_WRAPPER_NONE && mono_use_imt) {
6707                                         g_assert (!imt_arg);
6708                                         if (!context_used)
6709                                                 g_assert (cmethod->is_inflated);
6710                                         imt_arg = emit_get_rgctx_method (cfg, context_used,
6711                                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
6712                                         ins = mono_emit_method_call_full (cfg, cmethod, fsig, sp, sp [0], imt_arg);
6713                                 } else
6714 #endif
6715                                 {
6716                                         this_temp = mono_compile_create_var (cfg, type_from_stack_type (sp [0]), OP_LOCAL);
6717                                         NEW_TEMPSTORE (cfg, store, this_temp->inst_c0, sp [0]);
6718                                         MONO_ADD_INS (bblock, store);
6719
6720                                         /* FIXME: This should be a managed pointer */
6721                                         this_arg_temp = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
6722
6723                                         EMIT_NEW_TEMPLOAD (cfg, iargs [0], this_temp->inst_c0);
6724                                         iargs [1] = emit_get_rgctx_method (cfg, context_used,
6725                                                                                                            cmethod, MONO_RGCTX_INFO_METHOD);
6726                                         EMIT_NEW_TEMPLOADA (cfg, iargs [2], this_arg_temp->inst_c0);
6727                                         addr = mono_emit_jit_icall (cfg,
6728                                                                                                 mono_helper_compile_generic_method, iargs);
6729
6730                                         EMIT_NEW_TEMPLOAD (cfg, sp [0], this_arg_temp->inst_c0);
6731
6732                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6733                                 }
6734
6735                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6736                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6737
6738                                 CHECK_CFG_EXCEPTION;
6739
6740                                 ip += 5;
6741                                 ins_flag = 0;
6742                                 break;
6743                         }
6744
6745 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6746                         supported_tail_call = cmethod && MONO_ARCH_USE_OP_TAIL_CALL (mono_method_signature (method), mono_method_signature (cmethod));
6747 #else
6748                         supported_tail_call = cmethod && mono_metadata_signature_equal (mono_method_signature (method), mono_method_signature (cmethod)) && !MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->ret);
6749 #endif
6750
6751                         /* Tail prefix */
6752                         /* FIXME: runtime generic context pointer for jumps? */
6753                         /* FIXME: handle this for generic sharing eventually */
6754                         if ((ins_flag & MONO_INST_TAILCALL) && !cfg->generic_sharing_context && !vtable_arg && cmethod && (*ip == CEE_CALL) && supported_tail_call) {
6755                                 MonoCallInst *call;
6756
6757                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6758                                 INLINE_FAILURE;
6759
6760 #ifdef MONO_ARCH_USE_OP_TAIL_CALL
6761                                 /* Handle tail calls similarly to calls */
6762                                 call = mono_emit_call_args (cfg, mono_method_signature (cmethod), sp, FALSE, FALSE, TRUE);
6763 #else
6764                                 MONO_INST_NEW_CALL (cfg, call, OP_JMP);
6765                                 call->tail_call = TRUE;
6766                                 call->method = cmethod;
6767                                 call->signature = mono_method_signature (cmethod);
6768
6769                                 /*
6770                                  * We implement tail calls by storing the actual arguments into the 
6771                                  * argument variables, then emitting a CEE_JMP.
6772                                  */
6773                                 for (i = 0; i < n; ++i) {
6774                                         /* Prevent argument from being register allocated */
6775                                         arg_array [i]->flags |= MONO_INST_VOLATILE;
6776                                         EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
6777                                 }
6778 #endif
6779
6780                                 ins = (MonoInst*)call;
6781                                 ins->inst_p0 = cmethod;
6782                                 ins->inst_p1 = arg_array [0];
6783                                 MONO_ADD_INS (bblock, ins);
6784                                 link_bblock (cfg, bblock, end_bblock);                  
6785                                 start_new_bblock = 1;
6786
6787                                 CHECK_CFG_EXCEPTION;
6788
6789                                 /* skip CEE_RET as well */
6790                                 ip += 6;
6791                                 ins_flag = 0;
6792                                 break;
6793                         }
6794
6795                         /*
6796                          * Implement a workaround for the inherent races involved in locking:
6797                          * Monitor.Enter ()
6798                          * try {
6799                          * } finally {
6800                          *    Monitor.Exit ()
6801                          * }
6802                          * If a thread abort happens between the call to Monitor.Enter () and the start of the
6803                          * try block, the Exit () won't be executed, see:
6804                          * http://www.bluebytesoftware.com/blog/2007/01/30/MonitorEnterThreadAbortsAndOrphanedLocks.aspx
6805                          * To work around this, we extend such try blocks to include the last x bytes
6806                          * of the Monitor.Enter () call.
6807                          */
6808                         if (cmethod && cmethod->klass == mono_defaults.monitor_class && !strcmp (cmethod->name, "Enter") && mono_method_signature (cmethod)->param_count == 1) {
6809                                 MonoBasicBlock *tbb;
6810
6811                                 GET_BBLOCK (cfg, tbb, ip + 5);
6812                                 /* 
6813                                  * Only extend try blocks with a finally, to avoid catching exceptions thrown
6814                                  * from Monitor.Enter like ArgumentNullException.
6815                                  */
6816                                 if (tbb->try_start && MONO_REGION_FLAGS(tbb->region) == MONO_EXCEPTION_CLAUSE_FINALLY) {
6817                                         /* Mark this bblock as needing to be extended */
6818                                         tbb->extend_try_block = TRUE;
6819                                 }
6820                         }
6821
6822                         /* Conversion to a JIT intrinsic */
6823                         if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_method (cfg, cmethod, fsig, sp))) {
6824                                 bblock = cfg->cbb;
6825                                 if (!MONO_TYPE_IS_VOID (fsig->ret)) {
6826                                         type_to_eval_stack_type ((cfg), fsig->ret, ins);
6827                                         *sp = ins;
6828                                         sp++;
6829                                 }
6830
6831                                 CHECK_CFG_EXCEPTION;
6832
6833                                 ip += 5;
6834                                 ins_flag = 0;
6835                                 break;
6836                         }
6837
6838                         /* Inlining */
6839                         if ((cfg->opt & MONO_OPT_INLINE) && cmethod &&
6840                                 (!virtual || !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL) || MONO_METHOD_IS_FINAL (cmethod)) &&
6841                             !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
6842                                  !g_list_find (dont_inline, cmethod)) {
6843                                 int costs;
6844                                 gboolean always = FALSE;
6845
6846                                 if ((cmethod->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) ||
6847                                         (cmethod->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)) {
6848                                         /* Prevent inlining of methods that call wrappers */
6849                                         INLINE_FAILURE;
6850                                         cmethod = mono_marshal_get_native_wrapper (cmethod, check_for_pending_exc, FALSE);
6851                                         always = TRUE;
6852                                 }
6853
6854                                 if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, always))) {
6855                                         ip += 5;
6856                                         cfg->real_offset += 5;
6857                                         bblock = cfg->cbb;
6858
6859                                         if (!MONO_TYPE_IS_VOID (fsig->ret))
6860                                                 /* *sp is already set by inline_method */
6861                                                 sp++;
6862
6863                                         inline_costs += costs;
6864                                         ins_flag = 0;
6865                                         break;
6866                                 }
6867                         }
6868                         
6869                         inline_costs += 10 * num_calls++;
6870
6871                         /* Tail recursion elimination */
6872                         if ((cfg->opt & MONO_OPT_TAILC) && *ip == CEE_CALL && cmethod == method && ip [5] == CEE_RET && !vtable_arg) {
6873                                 gboolean has_vtargs = FALSE;
6874                                 int i;
6875
6876                                 /* Prevent inlining of methods with tail calls (the call stack would be altered) */
6877                                 INLINE_FAILURE;
6878
6879                                 /* keep it simple */
6880                                 for (i =  fsig->param_count - 1; i >= 0; i--) {
6881                                         if (MONO_TYPE_ISSTRUCT (mono_method_signature (cmethod)->params [i])) 
6882                                                 has_vtargs = TRUE;
6883                                 }
6884
6885                                 if (!has_vtargs) {
6886                                         for (i = 0; i < n; ++i)
6887                                                 EMIT_NEW_ARGSTORE (cfg, ins, i, sp [i]);
6888                                         MONO_INST_NEW (cfg, ins, OP_BR);
6889                                         MONO_ADD_INS (bblock, ins);
6890                                         tblock = start_bblock->out_bb [0];
6891                                         link_bblock (cfg, bblock, tblock);
6892                                         ins->inst_target_bb = tblock;
6893                                         start_new_bblock = 1;
6894
6895                                         /* skip the CEE_RET, too */
6896                                         if (ip_in_bb (cfg, bblock, ip + 5))
6897                                                 ip += 6;
6898                                         else
6899                                                 ip += 5;
6900
6901                                         ins_flag = 0;
6902                                         break;
6903                                 }
6904                         }
6905
6906                         /* Generic sharing */
6907                         /* FIXME: only do this for generic methods if
6908                            they are not shared! */
6909                         if (context_used && !imt_arg && !array_rank &&
6910                                         (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
6911                                                 !mono_class_generic_sharing_enabled (cmethod->klass)) &&
6912                                         (!virtual || MONO_METHOD_IS_FINAL (cmethod) ||
6913                                                 !(cmethod->flags & METHOD_ATTRIBUTE_VIRTUAL))) {
6914                                 INLINE_FAILURE;
6915
6916                                 g_assert (cfg->generic_sharing_context && cmethod);
6917                                 g_assert (!addr);
6918
6919                                 /*
6920                                  * We are compiling a call to a
6921                                  * generic method from shared code,
6922                                  * which means that we have to look up
6923                                  * the method in the rgctx and do an
6924                                  * indirect call.
6925                                  */
6926                                 addr = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
6927                         }
6928
6929                         /* Indirect calls */
6930                         if (addr) {
6931                                 g_assert (!imt_arg);
6932
6933                                 if (*ip == CEE_CALL)
6934                                         g_assert (context_used);
6935                                 else if (*ip == CEE_CALLI)
6936                                         g_assert (!vtable_arg);
6937                                 else
6938                                         /* FIXME: what the hell is this??? */
6939                                         g_assert (cmethod->flags & METHOD_ATTRIBUTE_FINAL ||
6940                                                         !(cmethod->flags & METHOD_ATTRIBUTE_FINAL));
6941
6942                                 /* Prevent inlining of methods with indirect calls */
6943                                 INLINE_FAILURE;
6944
6945                                 if (vtable_arg) {
6946                                         MonoCallInst *call;
6947                                         int rgctx_reg = mono_alloc_preg (cfg);
6948
6949                                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, rgctx_reg, vtable_arg->dreg);
6950                                         ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6951                                         call = (MonoCallInst*)ins;
6952                                         set_rgctx_arg (cfg, call, rgctx_reg, vtable_arg);
6953                                 } else {
6954                                         if (addr->opcode == OP_AOTCONST && addr->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
6955                                                 /* 
6956                                                  * Instead of emitting an indirect call, emit a direct call
6957                                                  * with the contents of the aotconst as the patch info.
6958                                                  */
6959                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_p0, fsig, sp);
6960                                                 NULLIFY_INS (addr);
6961                                         } else if (addr->opcode == OP_GOT_ENTRY && addr->inst_right->inst_c1 == MONO_PATCH_INFO_ICALL_ADDR) {
6962                                                 ins = (MonoInst*)mono_emit_abs_call (cfg, MONO_PATCH_INFO_ICALL_ADDR, addr->inst_right->inst_left, fsig, sp);
6963                                                 NULLIFY_INS (addr);
6964                                         } else {
6965                                                 ins = (MonoInst*)mono_emit_calli (cfg, fsig, sp, addr);
6966                                         }
6967                                 }
6968                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
6969                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
6970
6971                                 CHECK_CFG_EXCEPTION;
6972
6973                                 ip += 5;
6974                                 ins_flag = 0;
6975                                 break;
6976                         }
6977                                         
6978                         /* Array methods */
6979                         if (array_rank) {
6980                                 MonoInst *addr;
6981
6982                                 if (strcmp (cmethod->name, "Set") == 0) { /* array Set */ 
6983                                         if (sp [fsig->param_count]->type == STACK_OBJ) {
6984                                                 MonoInst *iargs [2];
6985
6986                                                 iargs [0] = sp [0];
6987                                                 iargs [1] = sp [fsig->param_count];
6988                                                 
6989                                                 mono_emit_jit_icall (cfg, mono_helper_stelem_ref_check, iargs);
6990                                         }
6991                                         
6992                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, TRUE);
6993                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, fsig->params [fsig->param_count - 1], addr->dreg, 0, sp [fsig->param_count]->dreg);
6994                                 } else if (strcmp (cmethod->name, "Get") == 0) { /* array Get */
6995                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
6996
6997                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, fsig->ret, addr->dreg, 0);
6998
6999                                         *sp++ = ins;
7000                                 } else if (strcmp (cmethod->name, "Address") == 0) { /* array Address */
7001                                         if (!cmethod->klass->element_class->valuetype && !readonly)
7002                                                 mini_emit_check_array_type (cfg, sp [0], cmethod->klass);
7003                                         CHECK_TYPELOAD (cmethod->klass);
7004                                         
7005                                         readonly = FALSE;
7006                                         addr = mini_emit_ldelema_ins (cfg, cmethod, sp, ip, FALSE);
7007                                         *sp++ = addr;
7008                                 } else {
7009                                         g_assert_not_reached ();
7010                                 }
7011
7012                                 CHECK_CFG_EXCEPTION;
7013
7014                                 ip += 5;
7015                                 ins_flag = 0;
7016                                 break;
7017                         }
7018
7019                         ins = mini_redirect_call (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL);
7020                         if (ins) {
7021                                 if (!MONO_TYPE_IS_VOID (fsig->ret))
7022                                         *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
7023
7024                                 CHECK_CFG_EXCEPTION;
7025
7026                                 ip += 5;
7027                                 ins_flag = 0;
7028                                 break;
7029                         }
7030
7031                         /* Common call */
7032                         INLINE_FAILURE;
7033                         if (vtable_arg) {
7034                                 ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL,
7035                                         NULL, vtable_arg);
7036                         } else if (imt_arg) {
7037                                 ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, imt_arg);
7038                         } else {
7039                                 ins = (MonoInst*)mono_emit_method_call_full (cfg, cmethod, fsig, sp, virtual ? sp [0] : NULL, NULL);
7040                         }
7041
7042                         if (!MONO_TYPE_IS_VOID (fsig->ret))
7043                                 *sp++ = mono_emit_widen_call_res (cfg, ins, fsig);
7044
7045                         CHECK_CFG_EXCEPTION;
7046
7047                         ip += 5;
7048                         ins_flag = 0;
7049                         break;
7050                 }
7051                 case CEE_RET:
7052                         if (cfg->method != method) {
7053                                 /* return from inlined method */
7054                                 /* 
7055                                  * If in_count == 0, that means the ret is unreachable due to
7056                                  * being preceeded by a throw. In that case, inline_method () will
7057                                  * handle setting the return value 
7058                                  * (test case: test_0_inline_throw ()).
7059                                  */
7060                                 if (return_var && cfg->cbb->in_count) {
7061                                         MonoInst *store;
7062                                         CHECK_STACK (1);
7063                                         --sp;
7064                                         //g_assert (returnvar != -1);
7065                                         EMIT_NEW_TEMPSTORE (cfg, store, return_var->inst_c0, *sp);
7066                                         cfg->ret_var_set = TRUE;
7067                                 } 
7068                         } else {
7069                                 if (cfg->ret) {
7070                                         MonoType *ret_type = mono_method_signature (method)->ret;
7071
7072                                         if (seq_points) {
7073                                                 /* 
7074                                                  * Place a seq point here too even through the IL stack is not
7075                                                  * empty, so a step over on
7076                                                  * call <FOO>
7077                                                  * ret
7078                                                  * will work correctly.
7079                                                  */
7080                                                 NEW_SEQ_POINT (cfg, ins, ip - header->code, TRUE);
7081                                                 MONO_ADD_INS (cfg->cbb, ins);
7082                                         }
7083
7084                                         g_assert (!return_var);
7085                                         CHECK_STACK (1);
7086                                         --sp;
7087                                         if (mini_type_to_stind (cfg, ret_type) == CEE_STOBJ) {
7088                                                 MonoInst *ret_addr;
7089
7090                                                 if (!cfg->vret_addr) {
7091                                                         MonoInst *ins;
7092
7093                                                         EMIT_NEW_VARSTORE (cfg, ins, cfg->ret, ret_type, (*sp));
7094                                                 } else {
7095                                                         EMIT_NEW_RETLOADA (cfg, ret_addr);
7096
7097                                                         EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STOREV_MEMBASE, ret_addr->dreg, 0, (*sp)->dreg);
7098                                                         ins->klass = mono_class_from_mono_type (ret_type);
7099                                                 }
7100                                         } else {
7101 #ifdef MONO_ARCH_SOFT_FLOAT
7102                                                 if (COMPILE_SOFT_FLOAT (cfg) && !ret_type->byref && ret_type->type == MONO_TYPE_R4) {
7103                                                         MonoInst *iargs [1];
7104                                                         MonoInst *conv;
7105
7106                                                         iargs [0] = *sp;
7107                                                         conv = mono_emit_jit_icall (cfg, mono_fload_r4_arg, iargs);
7108                                                         mono_arch_emit_setret (cfg, method, conv);
7109                                                 } else {
7110                                                         mono_arch_emit_setret (cfg, method, *sp);
7111                                                 }
7112 #else
7113                                                 mono_arch_emit_setret (cfg, method, *sp);
7114 #endif
7115                                         }
7116                                 }
7117                         }
7118                         if (sp != stack_start)
7119                                 UNVERIFIED;
7120                         MONO_INST_NEW (cfg, ins, OP_BR);
7121                         ip++;
7122                         ins->inst_target_bb = end_bblock;
7123                         MONO_ADD_INS (bblock, ins);
7124                         link_bblock (cfg, bblock, end_bblock);
7125                         start_new_bblock = 1;
7126                         break;
7127                 case CEE_BR_S:
7128                         CHECK_OPSIZE (2);
7129                         MONO_INST_NEW (cfg, ins, OP_BR);
7130                         ip++;
7131                         target = ip + 1 + (signed char)(*ip);
7132                         ++ip;
7133                         GET_BBLOCK (cfg, tblock, target);
7134                         link_bblock (cfg, bblock, tblock);
7135                         ins->inst_target_bb = tblock;
7136                         if (sp != stack_start) {
7137                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7138                                 sp = stack_start;
7139                                 CHECK_UNVERIFIABLE (cfg);
7140                         }
7141                         MONO_ADD_INS (bblock, ins);
7142                         start_new_bblock = 1;
7143                         inline_costs += BRANCH_COST;
7144                         break;
7145                 case CEE_BEQ_S:
7146                 case CEE_BGE_S:
7147                 case CEE_BGT_S:
7148                 case CEE_BLE_S:
7149                 case CEE_BLT_S:
7150                 case CEE_BNE_UN_S:
7151                 case CEE_BGE_UN_S:
7152                 case CEE_BGT_UN_S:
7153                 case CEE_BLE_UN_S:
7154                 case CEE_BLT_UN_S:
7155                         CHECK_OPSIZE (2);
7156                         CHECK_STACK (2);
7157                         MONO_INST_NEW (cfg, ins, *ip + BIG_BRANCH_OFFSET);
7158                         ip++;
7159                         target = ip + 1 + *(signed char*)ip;
7160                         ip++;
7161
7162                         ADD_BINCOND (NULL);
7163
7164                         sp = stack_start;
7165                         inline_costs += BRANCH_COST;
7166                         break;
7167                 case CEE_BR:
7168                         CHECK_OPSIZE (5);
7169                         MONO_INST_NEW (cfg, ins, OP_BR);
7170                         ip++;
7171
7172                         target = ip + 4 + (gint32)read32(ip);
7173                         ip += 4;
7174                         GET_BBLOCK (cfg, tblock, target);
7175                         link_bblock (cfg, bblock, tblock);
7176                         ins->inst_target_bb = tblock;
7177                         if (sp != stack_start) {
7178                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7179                                 sp = stack_start;
7180                                 CHECK_UNVERIFIABLE (cfg);
7181                         }
7182
7183                         MONO_ADD_INS (bblock, ins);
7184
7185                         start_new_bblock = 1;
7186                         inline_costs += BRANCH_COST;
7187                         break;
7188                 case CEE_BRFALSE_S:
7189                 case CEE_BRTRUE_S:
7190                 case CEE_BRFALSE:
7191                 case CEE_BRTRUE: {
7192                         MonoInst *cmp;
7193                         gboolean is_short = ((*ip) == CEE_BRFALSE_S) || ((*ip) == CEE_BRTRUE_S);
7194                         gboolean is_true = ((*ip) == CEE_BRTRUE_S) || ((*ip) == CEE_BRTRUE);
7195                         guint32 opsize = is_short ? 1 : 4;
7196
7197                         CHECK_OPSIZE (opsize);
7198                         CHECK_STACK (1);
7199                         if (sp [-1]->type == STACK_VTYPE || sp [-1]->type == STACK_R8)
7200                                 UNVERIFIED;
7201                         ip ++;
7202                         target = ip + opsize + (is_short ? *(signed char*)ip : (gint32)read32(ip));
7203                         ip += opsize;
7204
7205                         sp--;
7206
7207                         GET_BBLOCK (cfg, tblock, target);
7208                         link_bblock (cfg, bblock, tblock);
7209                         GET_BBLOCK (cfg, tblock, ip);
7210                         link_bblock (cfg, bblock, tblock);
7211
7212                         if (sp != stack_start) {
7213                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7214                                 CHECK_UNVERIFIABLE (cfg);
7215                         }
7216
7217                         MONO_INST_NEW(cfg, cmp, OP_ICOMPARE_IMM);
7218                         cmp->sreg1 = sp [0]->dreg;
7219                         type_from_op (cmp, sp [0], NULL);
7220                         CHECK_TYPE (cmp);
7221
7222 #if SIZEOF_REGISTER == 4
7223                         if (cmp->opcode == OP_LCOMPARE_IMM) {
7224                                 /* Convert it to OP_LCOMPARE */
7225                                 MONO_INST_NEW (cfg, ins, OP_I8CONST);
7226                                 ins->type = STACK_I8;
7227                                 ins->dreg = alloc_dreg (cfg, STACK_I8);
7228                                 ins->inst_l = 0;
7229                                 MONO_ADD_INS (bblock, ins);
7230                                 cmp->opcode = OP_LCOMPARE;
7231                                 cmp->sreg2 = ins->dreg;
7232                         }
7233 #endif
7234                         MONO_ADD_INS (bblock, cmp);
7235
7236                         MONO_INST_NEW (cfg, ins, is_true ? CEE_BNE_UN : CEE_BEQ);
7237                         type_from_op (ins, sp [0], NULL);
7238                         MONO_ADD_INS (bblock, ins);
7239                         ins->inst_many_bb = mono_mempool_alloc (cfg->mempool, sizeof(gpointer)*2);
7240                         GET_BBLOCK (cfg, tblock, target);
7241                         ins->inst_true_bb = tblock;
7242                         GET_BBLOCK (cfg, tblock, ip);
7243                         ins->inst_false_bb = tblock;
7244                         start_new_bblock = 2;
7245
7246                         sp = stack_start;
7247                         inline_costs += BRANCH_COST;
7248                         break;
7249                 }
7250                 case CEE_BEQ:
7251                 case CEE_BGE:
7252                 case CEE_BGT:
7253                 case CEE_BLE:
7254                 case CEE_BLT:
7255                 case CEE_BNE_UN:
7256                 case CEE_BGE_UN:
7257                 case CEE_BGT_UN:
7258                 case CEE_BLE_UN:
7259                 case CEE_BLT_UN:
7260                         CHECK_OPSIZE (5);
7261                         CHECK_STACK (2);
7262                         MONO_INST_NEW (cfg, ins, *ip);
7263                         ip++;
7264                         target = ip + 4 + (gint32)read32(ip);
7265                         ip += 4;
7266
7267                         ADD_BINCOND (NULL);
7268
7269                         sp = stack_start;
7270                         inline_costs += BRANCH_COST;
7271                         break;
7272                 case CEE_SWITCH: {
7273                         MonoInst *src1;
7274                         MonoBasicBlock **targets;
7275                         MonoBasicBlock *default_bblock;
7276                         MonoJumpInfoBBTable *table;
7277                         int offset_reg = alloc_preg (cfg);
7278                         int target_reg = alloc_preg (cfg);
7279                         int table_reg = alloc_preg (cfg);
7280                         int sum_reg = alloc_preg (cfg);
7281                         gboolean use_op_switch;
7282
7283                         CHECK_OPSIZE (5);
7284                         CHECK_STACK (1);
7285                         n = read32 (ip + 1);
7286                         --sp;
7287                         src1 = sp [0];
7288                         if ((src1->type != STACK_I4) && (src1->type != STACK_PTR)) 
7289                                 UNVERIFIED;
7290
7291                         ip += 5;
7292                         CHECK_OPSIZE (n * sizeof (guint32));
7293                         target = ip + n * sizeof (guint32);
7294
7295                         GET_BBLOCK (cfg, default_bblock, target);
7296                         default_bblock->flags |= BB_INDIRECT_JUMP_TARGET;
7297
7298                         targets = mono_mempool_alloc (cfg->mempool, sizeof (MonoBasicBlock*) * n);
7299                         for (i = 0; i < n; ++i) {
7300                                 GET_BBLOCK (cfg, tblock, target + (gint32)read32(ip));
7301                                 targets [i] = tblock;
7302                                 targets [i]->flags |= BB_INDIRECT_JUMP_TARGET;
7303                                 ip += 4;
7304                         }
7305
7306                         if (sp != stack_start) {
7307                                 /* 
7308                                  * Link the current bb with the targets as well, so handle_stack_args
7309                                  * will set their in_stack correctly.
7310                                  */
7311                                 link_bblock (cfg, bblock, default_bblock);
7312                                 for (i = 0; i < n; ++i)
7313                                         link_bblock (cfg, bblock, targets [i]);
7314
7315                                 handle_stack_args (cfg, stack_start, sp - stack_start);
7316                                 sp = stack_start;
7317                                 CHECK_UNVERIFIABLE (cfg);
7318                         }
7319
7320                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ICOMPARE_IMM, -1, src1->dreg, n);
7321                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_IBGE_UN, default_bblock);
7322                         bblock = cfg->cbb;
7323
7324                         for (i = 0; i < n; ++i)
7325                                 link_bblock (cfg, bblock, targets [i]);
7326
7327                         table = mono_mempool_alloc (cfg->mempool, sizeof (MonoJumpInfoBBTable));
7328                         table->table = targets;
7329                         table->table_size = n;
7330
7331                         use_op_switch = FALSE;
7332 #ifdef TARGET_ARM
7333                         /* ARM implements SWITCH statements differently */
7334                         /* FIXME: Make it use the generic implementation */
7335                         if (!cfg->compile_aot)
7336                                 use_op_switch = TRUE;
7337 #endif
7338
7339                         if (COMPILE_LLVM (cfg))
7340                                 use_op_switch = TRUE;
7341
7342                         cfg->cbb->has_jump_table = 1;
7343
7344                         if (use_op_switch) {
7345                                 MONO_INST_NEW (cfg, ins, OP_SWITCH);
7346                                 ins->sreg1 = src1->dreg;
7347                                 ins->inst_p0 = table;
7348                                 ins->inst_many_bb = targets;
7349                                 ins->klass = GUINT_TO_POINTER (n);
7350                                 MONO_ADD_INS (cfg->cbb, ins);
7351                         } else {
7352                                 if (sizeof (gpointer) == 8)
7353                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 3);
7354                                 else
7355                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_SHL_IMM, offset_reg, src1->dreg, 2);
7356
7357 #if SIZEOF_REGISTER == 8
7358                                 /* The upper word might not be zero, and we add it to a 64 bit address later */
7359                                 MONO_EMIT_NEW_UNALU (cfg, OP_ZEXT_I4, offset_reg, offset_reg);
7360 #endif
7361
7362                                 if (cfg->compile_aot) {
7363                                         MONO_EMIT_NEW_AOTCONST (cfg, table_reg, table, MONO_PATCH_INFO_SWITCH);
7364                                 } else {
7365                                         MONO_INST_NEW (cfg, ins, OP_JUMP_TABLE);
7366                                         ins->inst_c1 = MONO_PATCH_INFO_SWITCH;
7367                                         ins->inst_p0 = table;
7368                                         ins->dreg = table_reg;
7369                                         MONO_ADD_INS (cfg->cbb, ins);
7370                                 }
7371
7372                                 /* FIXME: Use load_memindex */
7373                                 MONO_EMIT_NEW_BIALU (cfg, OP_PADD, sum_reg, table_reg, offset_reg);
7374                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, target_reg, sum_reg, 0);
7375                                 MONO_EMIT_NEW_UNALU (cfg, OP_BR_REG, -1, target_reg);
7376                         }
7377                         start_new_bblock = 1;
7378                         inline_costs += (BRANCH_COST * 2);
7379                         break;
7380                 }
7381                 case CEE_LDIND_I1:
7382                 case CEE_LDIND_U1:
7383                 case CEE_LDIND_I2:
7384                 case CEE_LDIND_U2:
7385                 case CEE_LDIND_I4:
7386                 case CEE_LDIND_U4:
7387                 case CEE_LDIND_I8:
7388                 case CEE_LDIND_I:
7389                 case CEE_LDIND_R4:
7390                 case CEE_LDIND_R8:
7391                 case CEE_LDIND_REF:
7392                         CHECK_STACK (1);
7393                         --sp;
7394
7395                         switch (*ip) {
7396                         case CEE_LDIND_R4:
7397                         case CEE_LDIND_R8:
7398                                 dreg = alloc_freg (cfg);
7399                                 break;
7400                         case CEE_LDIND_I8:
7401                                 dreg = alloc_lreg (cfg);
7402                                 break;
7403                         default:
7404                                 dreg = alloc_preg (cfg);
7405                         }
7406
7407                         NEW_LOAD_MEMBASE (cfg, ins, ldind_to_load_membase (*ip), dreg, sp [0]->dreg, 0);
7408                         ins->type = ldind_type [*ip - CEE_LDIND_I1];
7409                         ins->flags |= ins_flag;
7410                         ins_flag = 0;
7411                         MONO_ADD_INS (bblock, ins);
7412                         *sp++ = ins;
7413                         ++ip;
7414                         break;
7415                 case CEE_STIND_REF:
7416                 case CEE_STIND_I1:
7417                 case CEE_STIND_I2:
7418                 case CEE_STIND_I4:
7419                 case CEE_STIND_I8:
7420                 case CEE_STIND_R4:
7421                 case CEE_STIND_R8:
7422                 case CEE_STIND_I:
7423                         CHECK_STACK (2);
7424                         sp -= 2;
7425
7426                         NEW_STORE_MEMBASE (cfg, ins, stind_to_store_membase (*ip), sp [0]->dreg, 0, sp [1]->dreg);
7427                         ins->flags |= ins_flag;
7428                         ins_flag = 0;
7429                         MONO_ADD_INS (bblock, ins);
7430
7431                         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)))
7432                                 emit_write_barrier (cfg, sp [0], sp [1], -1);
7433
7434                         inline_costs += 1;
7435                         ++ip;
7436                         break;
7437
7438                 case CEE_MUL:
7439                         CHECK_STACK (2);
7440
7441                         MONO_INST_NEW (cfg, ins, (*ip));
7442                         sp -= 2;
7443                         ins->sreg1 = sp [0]->dreg;
7444                         ins->sreg2 = sp [1]->dreg;
7445                         type_from_op (ins, sp [0], sp [1]);
7446                         CHECK_TYPE (ins);
7447                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
7448
7449                         /* Use the immediate opcodes if possible */
7450                         if ((sp [1]->opcode == OP_ICONST) && mono_arch_is_inst_imm (sp [1]->inst_c0)) {
7451                                 int imm_opcode = mono_op_to_op_imm (ins->opcode);
7452                                 if (imm_opcode != -1) {
7453                                         ins->opcode = imm_opcode;
7454                                         ins->inst_p1 = (gpointer)(gssize)(sp [1]->inst_c0);
7455                                         ins->sreg2 = -1;
7456
7457                                         sp [1]->opcode = OP_NOP;
7458                                 }
7459                         }
7460
7461                         MONO_ADD_INS ((cfg)->cbb, (ins));
7462
7463                         *sp++ = mono_decompose_opcode (cfg, ins);
7464                         ip++;
7465                         break;
7466                 case CEE_ADD:
7467                 case CEE_SUB:
7468                 case CEE_DIV:
7469                 case CEE_DIV_UN:
7470                 case CEE_REM:
7471                 case CEE_REM_UN:
7472                 case CEE_AND:
7473                 case CEE_OR:
7474                 case CEE_XOR:
7475                 case CEE_SHL:
7476                 case CEE_SHR:
7477                 case CEE_SHR_UN:
7478                         CHECK_STACK (2);
7479
7480                         MONO_INST_NEW (cfg, ins, (*ip));
7481                         sp -= 2;
7482                         ins->sreg1 = sp [0]->dreg;
7483                         ins->sreg2 = sp [1]->dreg;
7484                         type_from_op (ins, sp [0], sp [1]);
7485                         CHECK_TYPE (ins);
7486                         ADD_WIDEN_OP (ins, sp [0], sp [1]);
7487                         ins->dreg = alloc_dreg ((cfg), (ins)->type);
7488
7489                         /* FIXME: Pass opcode to is_inst_imm */
7490
7491                         /* Use the immediate opcodes if possible */
7492                         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)) {
7493                                 int imm_opcode;
7494
7495                                 imm_opcode = mono_op_to_op_imm_noemul (ins->opcode);
7496                                 if (imm_opcode != -1) {
7497                                         ins->opcode = imm_opcode;
7498                                         if (sp [1]->opcode == OP_I8CONST) {
7499 #if SIZEOF_REGISTER == 8
7500                                                 ins->inst_imm = sp [1]->inst_l;
7501 #else
7502                                                 ins->inst_ls_word = sp [1]->inst_ls_word;
7503                                                 ins->inst_ms_word = sp [1]->inst_ms_word;
7504 #endif
7505                                         }
7506                                         else
7507                                                 ins->inst_imm = (gssize)(sp [1]->inst_c0);
7508                                         ins->sreg2 = -1;
7509
7510                                         /* Might be followed by an instruction added by ADD_WIDEN_OP */
7511                                         if (sp [1]->next == NULL)
7512                                                 sp [1]->opcode = OP_NOP;
7513                                 }
7514                         }
7515                         MONO_ADD_INS ((cfg)->cbb, (ins));
7516
7517                         *sp++ = mono_decompose_opcode (cfg, ins);
7518                         ip++;
7519                         break;
7520                 case CEE_NEG:
7521                 case CEE_NOT:
7522                 case CEE_CONV_I1:
7523                 case CEE_CONV_I2:
7524                 case CEE_CONV_I4:
7525                 case CEE_CONV_R4:
7526                 case CEE_CONV_R8:
7527                 case CEE_CONV_U4:
7528                 case CEE_CONV_I8:
7529                 case CEE_CONV_U8:
7530                 case CEE_CONV_OVF_I8:
7531                 case CEE_CONV_OVF_U8:
7532                 case CEE_CONV_R_UN:
7533                         CHECK_STACK (1);
7534
7535                         /* Special case this earlier so we have long constants in the IR */
7536                         if ((((*ip) == CEE_CONV_I8) || ((*ip) == CEE_CONV_U8)) && (sp [-1]->opcode == OP_ICONST)) {
7537                                 int data = sp [-1]->inst_c0;
7538                                 sp [-1]->opcode = OP_I8CONST;
7539                                 sp [-1]->type = STACK_I8;
7540 #if SIZEOF_REGISTER == 8
7541                                 if ((*ip) == CEE_CONV_U8)
7542                                         sp [-1]->inst_c0 = (guint32)data;
7543                                 else
7544                                         sp [-1]->inst_c0 = data;
7545 #else
7546                                 sp [-1]->inst_ls_word = data;
7547                                 if ((*ip) == CEE_CONV_U8)
7548                                         sp [-1]->inst_ms_word = 0;
7549                                 else
7550                                         sp [-1]->inst_ms_word = (data < 0) ? -1 : 0;
7551 #endif
7552                                 sp [-1]->dreg = alloc_dreg (cfg, STACK_I8);
7553                         }
7554                         else {
7555                                 ADD_UNOP (*ip);
7556                         }
7557                         ip++;
7558                         break;
7559                 case CEE_CONV_OVF_I4:
7560                 case CEE_CONV_OVF_I1:
7561                 case CEE_CONV_OVF_I2:
7562                 case CEE_CONV_OVF_I:
7563                 case CEE_CONV_OVF_U:
7564                         CHECK_STACK (1);
7565
7566                         if (sp [-1]->type == STACK_R8) {
7567                                 ADD_UNOP (CEE_CONV_OVF_I8);
7568                                 ADD_UNOP (*ip);
7569                         } else {
7570                                 ADD_UNOP (*ip);
7571                         }
7572                         ip++;
7573                         break;
7574                 case CEE_CONV_OVF_U1:
7575                 case CEE_CONV_OVF_U2:
7576                 case CEE_CONV_OVF_U4:
7577                         CHECK_STACK (1);
7578
7579                         if (sp [-1]->type == STACK_R8) {
7580                                 ADD_UNOP (CEE_CONV_OVF_U8);
7581                                 ADD_UNOP (*ip);
7582                         } else {
7583                                 ADD_UNOP (*ip);
7584                         }
7585                         ip++;
7586                         break;
7587                 case CEE_CONV_OVF_I1_UN:
7588                 case CEE_CONV_OVF_I2_UN:
7589                 case CEE_CONV_OVF_I4_UN:
7590                 case CEE_CONV_OVF_I8_UN:
7591                 case CEE_CONV_OVF_U1_UN:
7592                 case CEE_CONV_OVF_U2_UN:
7593                 case CEE_CONV_OVF_U4_UN:
7594                 case CEE_CONV_OVF_U8_UN:
7595                 case CEE_CONV_OVF_I_UN:
7596                 case CEE_CONV_OVF_U_UN:
7597                 case CEE_CONV_U2:
7598                 case CEE_CONV_U1:
7599                 case CEE_CONV_I:
7600                 case CEE_CONV_U:
7601                         CHECK_STACK (1);
7602                         ADD_UNOP (*ip);
7603                         CHECK_CFG_EXCEPTION;
7604                         ip++;
7605                         break;
7606                 case CEE_ADD_OVF:
7607                 case CEE_ADD_OVF_UN:
7608                 case CEE_MUL_OVF:
7609                 case CEE_MUL_OVF_UN:
7610                 case CEE_SUB_OVF:
7611                 case CEE_SUB_OVF_UN:
7612                         CHECK_STACK (2);
7613                         ADD_BINOP (*ip);
7614                         ip++;
7615                         break;
7616                 case CEE_CPOBJ:
7617                         CHECK_OPSIZE (5);
7618                         CHECK_STACK (2);
7619                         token = read32 (ip + 1);
7620                         klass = mini_get_class (method, token, generic_context);
7621                         CHECK_TYPELOAD (klass);
7622                         sp -= 2;
7623                         if (generic_class_is_reference_type (cfg, klass)) {
7624                                 MonoInst *store, *load;
7625                                 int dreg = alloc_preg (cfg);
7626
7627                                 NEW_LOAD_MEMBASE (cfg, load, OP_LOAD_MEMBASE, dreg, sp [1]->dreg, 0);
7628                                 load->flags |= ins_flag;
7629                                 MONO_ADD_INS (cfg->cbb, load);
7630
7631                                 NEW_STORE_MEMBASE (cfg, store, OP_STORE_MEMBASE_REG, sp [0]->dreg, 0, dreg);
7632                                 store->flags |= ins_flag;
7633                                 MONO_ADD_INS (cfg->cbb, store);
7634
7635                                 if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER)
7636                                         emit_write_barrier (cfg, sp [0], sp [1], -1);
7637                         } else {
7638                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
7639                         }
7640                         ins_flag = 0;
7641                         ip += 5;
7642                         break;
7643                 case CEE_LDOBJ: {
7644                         int loc_index = -1;
7645                         int stloc_len = 0;
7646
7647                         CHECK_OPSIZE (5);
7648                         CHECK_STACK (1);
7649                         --sp;
7650                         token = read32 (ip + 1);
7651                         klass = mini_get_class (method, token, generic_context);
7652                         CHECK_TYPELOAD (klass);
7653
7654                         /* Optimize the common ldobj+stloc combination */
7655                         switch (ip [5]) {
7656                         case CEE_STLOC_S:
7657                                 loc_index = ip [6];
7658                                 stloc_len = 2;
7659                                 break;
7660                         case CEE_STLOC_0:
7661                         case CEE_STLOC_1:
7662                         case CEE_STLOC_2:
7663                         case CEE_STLOC_3:
7664                                 loc_index = ip [5] - CEE_STLOC_0;
7665                                 stloc_len = 1;
7666                                 break;
7667                         default:
7668                                 break;
7669                         }
7670
7671                         if ((loc_index != -1) && ip_in_bb (cfg, bblock, ip + 5)) {
7672                                 CHECK_LOCAL (loc_index);
7673
7674                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7675                                 ins->dreg = cfg->locals [loc_index]->dreg;
7676                                 ip += 5;
7677                                 ip += stloc_len;
7678                                 break;
7679                         }
7680
7681                         /* Optimize the ldobj+stobj combination */
7682                         /* The reference case ends up being a load+store anyway */
7683                         if (((ip [5] == CEE_STOBJ) && ip_in_bb (cfg, bblock, ip + 5) && read32 (ip + 6) == token) && !generic_class_is_reference_type (cfg, klass)) {
7684                                 CHECK_STACK (1);
7685
7686                                 sp --;
7687
7688                                 mini_emit_stobj (cfg, sp [0], sp [1], klass, FALSE);
7689
7690                                 ip += 5 + 5;
7691                                 ins_flag = 0;
7692                                 break;
7693                         }
7694
7695                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
7696                         *sp++ = ins;
7697
7698                         ip += 5;
7699                         ins_flag = 0;
7700                         inline_costs += 1;
7701                         break;
7702                 }
7703                 case CEE_LDSTR:
7704                         CHECK_STACK_OVF (1);
7705                         CHECK_OPSIZE (5);
7706                         n = read32 (ip + 1);
7707
7708                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
7709                                 EMIT_NEW_PCONST (cfg, ins, mono_method_get_wrapper_data (method, n));
7710                                 ins->type = STACK_OBJ;
7711                                 *sp = ins;
7712                         }
7713                         else if (method->wrapper_type != MONO_WRAPPER_NONE) {
7714                                 MonoInst *iargs [1];
7715
7716                                 EMIT_NEW_PCONST (cfg, iargs [0], mono_method_get_wrapper_data (method, n));                             
7717                                 *sp = mono_emit_jit_icall (cfg, mono_string_new_wrapper, iargs);
7718                         } else {
7719                                 if (cfg->opt & MONO_OPT_SHARED) {
7720                                         MonoInst *iargs [3];
7721
7722                                         if (cfg->compile_aot) {
7723                                                 cfg->ldstr_list = g_list_prepend (cfg->ldstr_list, GINT_TO_POINTER (n));
7724                                         }
7725                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
7726                                         EMIT_NEW_IMAGECONST (cfg, iargs [1], image);
7727                                         EMIT_NEW_ICONST (cfg, iargs [2], mono_metadata_token_index (n));
7728                                         *sp = mono_emit_jit_icall (cfg, mono_ldstr, iargs);
7729                                         mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7730                                 } else {
7731                                         if (bblock->out_of_line) {
7732                                                 MonoInst *iargs [2];
7733
7734                                                 if (image == mono_defaults.corlib) {
7735                                                         /* 
7736                                                          * Avoid relocations in AOT and save some space by using a 
7737                                                          * version of helper_ldstr specialized to mscorlib.
7738                                                          */
7739                                                         EMIT_NEW_ICONST (cfg, iargs [0], mono_metadata_token_index (n));
7740                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr_mscorlib, iargs);
7741                                                 } else {
7742                                                         /* Avoid creating the string object */
7743                                                         EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
7744                                                         EMIT_NEW_ICONST (cfg, iargs [1], mono_metadata_token_index (n));
7745                                                         *sp = mono_emit_jit_icall (cfg, mono_helper_ldstr, iargs);
7746                                                 }
7747                                         } 
7748                                         else
7749                                         if (cfg->compile_aot) {
7750                                                 NEW_LDSTRCONST (cfg, ins, image, n);
7751                                                 *sp = ins;
7752                                                 MONO_ADD_INS (bblock, ins);
7753                                         } 
7754                                         else {
7755                                                 NEW_PCONST (cfg, ins, NULL);
7756                                                 ins->type = STACK_OBJ;
7757                                                 ins->inst_p0 = mono_ldstr (cfg->domain, image, mono_metadata_token_index (n));
7758                                                 if (!ins->inst_p0)
7759                                                         OUT_OF_MEMORY_FAILURE;
7760
7761                                                 *sp = ins;
7762                                                 MONO_ADD_INS (bblock, ins);
7763                                         }
7764                                 }
7765                         }
7766
7767                         sp++;
7768                         ip += 5;
7769                         break;
7770                 case CEE_NEWOBJ: {
7771                         MonoInst *iargs [2];
7772                         MonoMethodSignature *fsig;
7773                         MonoInst this_ins;
7774                         MonoInst *alloc;
7775                         MonoInst *vtable_arg = NULL;
7776
7777                         CHECK_OPSIZE (5);
7778                         token = read32 (ip + 1);
7779                         cmethod = mini_get_method (cfg, method, token, NULL, generic_context);
7780                         if (!cmethod || mono_loader_get_last_error ())
7781                                 LOAD_ERROR;
7782                         fsig = mono_method_get_signature (cmethod, image, token);
7783                         if (!fsig)
7784                                 LOAD_ERROR;
7785
7786                         mono_save_token_info (cfg, image, token, cmethod);
7787
7788                         if (!mono_class_init (cmethod->klass))
7789                                 LOAD_ERROR;
7790
7791                         if (cfg->generic_sharing_context)
7792                                 context_used = mono_method_check_context_used (cmethod);
7793
7794                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
7795                                 if (check_linkdemand (cfg, method, cmethod))
7796                                         INLINE_FAILURE;
7797                                 CHECK_CFG_EXCEPTION;
7798                         } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
7799                                 ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
7800                         }
7801
7802                         if (cfg->generic_sharing_context && cmethod && cmethod->klass != method->klass && cmethod->klass->generic_class && mono_method_is_generic_sharable_impl (cmethod, TRUE) && mono_class_needs_cctor_run (cmethod->klass, method)) {
7803                                 emit_generic_class_init (cfg, cmethod->klass);
7804                                 CHECK_TYPELOAD (cmethod->klass);
7805                         }
7806
7807                         if (cmethod->klass->valuetype && mono_class_generic_sharing_enabled (cmethod->klass) &&
7808                                         mono_method_is_generic_sharable_impl (cmethod, TRUE)) {
7809                                 if (cmethod->is_inflated && mono_method_get_context (cmethod)->method_inst) {
7810                                         mono_class_vtable (cfg->domain, cmethod->klass);
7811                                         CHECK_TYPELOAD (cmethod->klass);
7812
7813                                         vtable_arg = emit_get_rgctx_method (cfg, context_used,
7814                                                                                                                 cmethod, MONO_RGCTX_INFO_METHOD_RGCTX);
7815                                 } else {
7816                                         if (context_used) {
7817                                                 vtable_arg = emit_get_rgctx_klass (cfg, context_used,
7818                                                         cmethod->klass, MONO_RGCTX_INFO_VTABLE);
7819                                         } else {
7820                                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7821
7822                                                 CHECK_TYPELOAD (cmethod->klass);
7823                                                 EMIT_NEW_VTABLECONST (cfg, vtable_arg, vtable);
7824                                         }
7825                                 }
7826                         }
7827
7828                         n = fsig->param_count;
7829                         CHECK_STACK (n);
7830
7831                         /* 
7832                          * Generate smaller code for the common newobj <exception> instruction in
7833                          * argument checking code.
7834                          */
7835                         if (bblock->out_of_line && cmethod->klass->image == mono_defaults.corlib &&
7836                                 is_exception_class (cmethod->klass) && n <= 2 &&
7837                                 ((n < 1) || (!fsig->params [0]->byref && fsig->params [0]->type == MONO_TYPE_STRING)) && 
7838                                 ((n < 2) || (!fsig->params [1]->byref && fsig->params [1]->type == MONO_TYPE_STRING))) {
7839                                 MonoInst *iargs [3];
7840
7841                                 g_assert (!vtable_arg);
7842
7843                                 sp -= n;
7844
7845                                 EMIT_NEW_ICONST (cfg, iargs [0], cmethod->klass->type_token);
7846                                 switch (n) {
7847                                 case 0:
7848                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_0, iargs);
7849                                         break;
7850                                 case 1:
7851                                         iargs [1] = sp [0];
7852                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_1, iargs);
7853                                         break;
7854                                 case 2:
7855                                         iargs [1] = sp [0];
7856                                         iargs [2] = sp [1];
7857                                         *sp ++ = mono_emit_jit_icall (cfg, mono_create_corlib_exception_2, iargs);
7858                                         break;
7859                                 default:
7860                                         g_assert_not_reached ();
7861                                 }
7862
7863                                 ip += 5;
7864                                 inline_costs += 5;
7865                                 break;
7866                         }
7867
7868                         /* move the args to allow room for 'this' in the first position */
7869                         while (n--) {
7870                                 --sp;
7871                                 sp [1] = sp [0];
7872                         }
7873
7874                         /* check_call_signature () requires sp[0] to be set */
7875                         this_ins.type = STACK_OBJ;
7876                         sp [0] = &this_ins;
7877                         if (check_call_signature (cfg, fsig, sp))
7878                                 UNVERIFIED;
7879
7880                         iargs [0] = NULL;
7881
7882                         if (mini_class_is_system_array (cmethod->klass)) {
7883                                 g_assert (!vtable_arg);
7884
7885                                 *sp = emit_get_rgctx_method (cfg, context_used,
7886                                                                                          cmethod, MONO_RGCTX_INFO_METHOD);
7887
7888                                 /* Avoid varargs in the common case */
7889                                 if (fsig->param_count == 1)
7890                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_1, sp);
7891                                 else if (fsig->param_count == 2)
7892                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_2, sp);
7893                                 else if (fsig->param_count == 3)
7894                                         alloc = mono_emit_jit_icall (cfg, mono_array_new_3, sp);
7895                                 else
7896                                         alloc = handle_array_new (cfg, fsig->param_count, sp, ip);
7897                         } else if (cmethod->string_ctor) {
7898                                 g_assert (!context_used);
7899                                 g_assert (!vtable_arg);
7900                                 /* we simply pass a null pointer */
7901                                 EMIT_NEW_PCONST (cfg, *sp, NULL); 
7902                                 /* now call the string ctor */
7903                                 alloc = mono_emit_method_call_full (cfg, cmethod, fsig, sp, NULL, NULL);
7904                         } else {
7905                                 MonoInst* callvirt_this_arg = NULL;
7906                                 
7907                                 if (cmethod->klass->valuetype) {
7908                                         iargs [0] = mono_compile_create_var (cfg, &cmethod->klass->byval_arg, OP_LOCAL);
7909                                         MONO_EMIT_NEW_VZERO (cfg, iargs [0]->dreg, cmethod->klass);
7910                                         EMIT_NEW_TEMPLOADA (cfg, *sp, iargs [0]->inst_c0);
7911
7912                                         alloc = NULL;
7913
7914                                         /* 
7915                                          * The code generated by mini_emit_virtual_call () expects
7916                                          * iargs [0] to be a boxed instance, but luckily the vcall
7917                                          * will be transformed into a normal call there.
7918                                          */
7919                                 } else if (context_used) {
7920                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, context_used);
7921                                         *sp = alloc;
7922                                 } else {
7923                                         MonoVTable *vtable = mono_class_vtable (cfg->domain, cmethod->klass);
7924
7925                                         CHECK_TYPELOAD (cmethod->klass);
7926
7927                                         /*
7928                                          * TypeInitializationExceptions thrown from the mono_runtime_class_init
7929                                          * call in mono_jit_runtime_invoke () can abort the finalizer thread.
7930                                          * As a workaround, we call class cctors before allocating objects.
7931                                          */
7932                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
7933                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
7934                                                 if (cfg->verbose_level > 2)
7935                                                         printf ("class %s.%s needs init call for ctor\n", cmethod->klass->name_space, cmethod->klass->name);
7936                                                 class_inits = g_slist_prepend (class_inits, vtable);
7937                                         }
7938
7939                                         alloc = handle_alloc (cfg, cmethod->klass, FALSE, 0);
7940                                         *sp = alloc;
7941                                 }
7942                                 CHECK_CFG_EXCEPTION; /*for handle_alloc*/
7943
7944                                 if (alloc)
7945                                         MONO_EMIT_NEW_UNALU (cfg, OP_NOT_NULL, -1, alloc->dreg);
7946
7947                                 /* Now call the actual ctor */
7948                                 /* Avoid virtual calls to ctors if possible */
7949                                 if (cmethod->klass->marshalbyref)
7950                                         callvirt_this_arg = sp [0];
7951
7952
7953                                 if (cmethod && (cfg->opt & MONO_OPT_INTRINS) && (ins = mini_emit_inst_for_ctor (cfg, cmethod, fsig, sp))) {
7954                                         if (!MONO_TYPE_IS_VOID (fsig->ret)) {
7955                                                 type_to_eval_stack_type ((cfg), fsig->ret, ins);
7956                                                 *sp = ins;
7957                                                 sp++;
7958                                         }
7959
7960                                         CHECK_CFG_EXCEPTION;
7961                                 } else if ((cfg->opt & MONO_OPT_INLINE) && cmethod && !context_used && !vtable_arg &&
7962                                     !disable_inline && mono_method_check_inlining (cfg, cmethod) &&
7963                                     !mono_class_is_subclass_of (cmethod->klass, mono_defaults.exception_class, FALSE) &&
7964                                     !g_list_find (dont_inline, cmethod)) {
7965                                         int costs;
7966
7967                                         if ((costs = inline_method (cfg, cmethod, fsig, sp, ip, cfg->real_offset, dont_inline, FALSE))) {
7968                                                 cfg->real_offset += 5;
7969                                                 bblock = cfg->cbb;
7970
7971                                                 inline_costs += costs - 5;
7972                                         } else {
7973                                                 INLINE_FAILURE;
7974                                                 mono_emit_method_call_full (cfg, cmethod, fsig, sp, callvirt_this_arg, NULL);
7975                                         }
7976                                 } else if (context_used &&
7977                                                 (!mono_method_is_generic_sharable_impl (cmethod, TRUE) ||
7978                                                         !mono_class_generic_sharing_enabled (cmethod->klass))) {
7979                                         MonoInst *cmethod_addr;
7980
7981                                         cmethod_addr = emit_get_rgctx_method (cfg, context_used,
7982                                                 cmethod, MONO_RGCTX_INFO_GENERIC_METHOD_CODE);
7983
7984                                         mono_emit_rgctx_calli (cfg, fsig, sp, cmethod_addr, vtable_arg);
7985                                 } else {
7986                                         INLINE_FAILURE;
7987                                         ins = mono_emit_rgctx_method_call_full (cfg, cmethod, fsig, sp,
7988                                                                                                                         callvirt_this_arg, NULL, vtable_arg);
7989                                 }
7990                         }
7991
7992                         if (alloc == NULL) {
7993                                 /* Valuetype */
7994                                 EMIT_NEW_TEMPLOAD (cfg, ins, iargs [0]->inst_c0);
7995                                 type_to_eval_stack_type (cfg, &ins->klass->byval_arg, ins);
7996                                 *sp++= ins;
7997                         }
7998                         else
7999                                 *sp++ = alloc;
8000                         
8001                         ip += 5;
8002                         inline_costs += 5;
8003                         break;
8004                 }
8005                 case CEE_CASTCLASS:
8006                         CHECK_STACK (1);
8007                         --sp;
8008                         CHECK_OPSIZE (5);
8009                         token = read32 (ip + 1);
8010                         klass = mini_get_class (method, token, generic_context);
8011                         CHECK_TYPELOAD (klass);
8012                         if (sp [0]->type != STACK_OBJ)
8013                                 UNVERIFIED;
8014
8015                         if (cfg->generic_sharing_context)
8016                                 context_used = mono_class_check_context_used (klass);
8017
8018                         if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
8019                                 MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
8020                                 MonoInst *args [3];
8021
8022                                 /* obj */
8023                                 args [0] = *sp;
8024
8025                                 /* klass */
8026                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
8027
8028                                 /* inline cache*/
8029                                 /*FIXME AOT support*/
8030                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
8031
8032                                 /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
8033                                 *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
8034                                 ip += 5;
8035                                 inline_costs += 2;
8036                         } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8037                                 MonoMethod *mono_castclass;
8038                                 MonoInst *iargs [1];
8039                                 int costs;
8040
8041                                 mono_castclass = mono_marshal_get_castclass (klass); 
8042                                 iargs [0] = sp [0];
8043                                 
8044                                 costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
8045                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
8046                                 CHECK_CFG_EXCEPTION;
8047                                 g_assert (costs > 0);
8048                                 
8049                                 ip += 5;
8050                                 cfg->real_offset += 5;
8051                                 bblock = cfg->cbb;
8052
8053                                 *sp++ = iargs [0];
8054
8055                                 inline_costs += costs;
8056                         }
8057                         else {
8058                                 ins = handle_castclass (cfg, klass, *sp, context_used);
8059                                 CHECK_CFG_EXCEPTION;
8060                                 bblock = cfg->cbb;
8061                                 *sp ++ = ins;
8062                                 ip += 5;
8063                         }
8064                         break;
8065                 case CEE_ISINST: {
8066                         CHECK_STACK (1);
8067                         --sp;
8068                         CHECK_OPSIZE (5);
8069                         token = read32 (ip + 1);
8070                         klass = mini_get_class (method, token, generic_context);
8071                         CHECK_TYPELOAD (klass);
8072                         if (sp [0]->type != STACK_OBJ)
8073                                 UNVERIFIED;
8074  
8075                         if (cfg->generic_sharing_context)
8076                                 context_used = mono_class_check_context_used (klass);
8077
8078                         if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
8079                                 MonoMethod *mono_isinst = mono_marshal_get_isinst_with_cache ();
8080                                 MonoInst *args [3];
8081
8082                                 /* obj */
8083                                 args [0] = *sp;
8084
8085                                 /* klass */
8086                                 EMIT_NEW_CLASSCONST (cfg, args [1], klass);
8087
8088                                 /* inline cache*/
8089                                 /*FIXME AOT support*/
8090                                 EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
8091
8092                                 *sp++ = mono_emit_method_call (cfg, mono_isinst, args, NULL);
8093                                 ip += 5;
8094                                 inline_costs += 2;
8095                         } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8096                                 MonoMethod *mono_isinst;
8097                                 MonoInst *iargs [1];
8098                                 int costs;
8099
8100                                 mono_isinst = mono_marshal_get_isinst (klass); 
8101                                 iargs [0] = sp [0];
8102
8103                                 costs = inline_method (cfg, mono_isinst, mono_method_signature (mono_isinst), 
8104                                                            iargs, ip, cfg->real_offset, dont_inline, TRUE);
8105                                 CHECK_CFG_EXCEPTION;
8106                                 g_assert (costs > 0);
8107                                 
8108                                 ip += 5;
8109                                 cfg->real_offset += 5;
8110                                 bblock = cfg->cbb;
8111
8112                                 *sp++= iargs [0];
8113
8114                                 inline_costs += costs;
8115                         }
8116                         else {
8117                                 ins = handle_isinst (cfg, klass, *sp, context_used);
8118                                 CHECK_CFG_EXCEPTION;
8119                                 bblock = cfg->cbb;
8120                                 *sp ++ = ins;
8121                                 ip += 5;
8122                         }
8123                         break;
8124                 }
8125                 case CEE_UNBOX_ANY: {
8126                         CHECK_STACK (1);
8127                         --sp;
8128                         CHECK_OPSIZE (5);
8129                         token = read32 (ip + 1);
8130                         klass = mini_get_class (method, token, generic_context);
8131                         CHECK_TYPELOAD (klass);
8132  
8133                         mono_save_token_info (cfg, image, token, klass);
8134
8135                         if (cfg->generic_sharing_context)
8136                                 context_used = mono_class_check_context_used (klass);
8137
8138                         if (generic_class_is_reference_type (cfg, klass)) {
8139                                 /* CASTCLASS FIXME kill this huge slice of duplicated code*/
8140                                 if (!context_used && mini_class_has_reference_variant_generic_argument (klass, context_used)) {
8141                                         MonoMethod *mono_castclass = mono_marshal_get_castclass_with_cache ();
8142                                         MonoInst *args [3];
8143
8144                                         /* obj */
8145                                         args [0] = *sp;
8146
8147                                         /* klass */
8148                                         EMIT_NEW_CLASSCONST (cfg, args [1], klass);
8149
8150                                         /* inline cache*/
8151                                         /*FIXME AOT support*/
8152                                         EMIT_NEW_PCONST (cfg, args [2], mono_domain_alloc0 (cfg->domain, sizeof (gpointer)));
8153
8154                                         /*The wrapper doesn't inline well so the bloat of inlining doesn't pay off.*/
8155                                         *sp++ = mono_emit_method_call (cfg, mono_castclass, args, NULL);
8156                                         ip += 5;
8157                                         inline_costs += 2;
8158                                 } else if (!context_used && (klass->marshalbyref || klass->flags & TYPE_ATTRIBUTE_INTERFACE)) {
8159                                         MonoMethod *mono_castclass;
8160                                         MonoInst *iargs [1];
8161                                         int costs;
8162
8163                                         mono_castclass = mono_marshal_get_castclass (klass); 
8164                                         iargs [0] = sp [0];
8165
8166                                         costs = inline_method (cfg, mono_castclass, mono_method_signature (mono_castclass), 
8167                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
8168                                         CHECK_CFG_EXCEPTION;
8169                                         g_assert (costs > 0);
8170                                 
8171                                         ip += 5;
8172                                         cfg->real_offset += 5;
8173                                         bblock = cfg->cbb;
8174
8175                                         *sp++ = iargs [0];
8176                                         inline_costs += costs;
8177                                 } else {
8178                                         ins = handle_castclass (cfg, klass, *sp, context_used);
8179                                         CHECK_CFG_EXCEPTION;
8180                                         bblock = cfg->cbb;
8181                                         *sp ++ = ins;
8182                                         ip += 5;
8183                                 }
8184                                 break;
8185                         }
8186
8187                         if (mono_class_is_nullable (klass)) {
8188                                 ins = handle_unbox_nullable (cfg, *sp, klass, context_used);
8189                                 *sp++= ins;
8190                                 ip += 5;
8191                                 break;
8192                         }
8193
8194                         /* UNBOX */
8195                         ins = handle_unbox (cfg, klass, sp, context_used);
8196                         *sp = ins;
8197
8198                         ip += 5;
8199
8200                         /* LDOBJ */
8201                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0);
8202                         *sp++ = ins;
8203
8204                         inline_costs += 2;
8205                         break;
8206                 }
8207                 case CEE_BOX: {
8208                         MonoInst *val;
8209
8210                         CHECK_STACK (1);
8211                         --sp;
8212                         val = *sp;
8213                         CHECK_OPSIZE (5);
8214                         token = read32 (ip + 1);
8215                         klass = mini_get_class (method, token, generic_context);
8216                         CHECK_TYPELOAD (klass);
8217
8218                         mono_save_token_info (cfg, image, token, klass);
8219
8220                         if (cfg->generic_sharing_context)
8221                                 context_used = mono_class_check_context_used (klass);
8222
8223                         if (generic_class_is_reference_type (cfg, klass)) {
8224                                 *sp++ = val;
8225                                 ip += 5;
8226                                 break;
8227                         }
8228
8229                         if (klass == mono_defaults.void_class)
8230                                 UNVERIFIED;
8231                         if (target_type_is_incompatible (cfg, &klass->byval_arg, *sp))
8232                                 UNVERIFIED;
8233                         /* frequent check in generic code: box (struct), brtrue */
8234
8235                         // FIXME: LLVM can't handle the inconsistent bb linking
8236                         if (!mono_class_is_nullable (klass) &&
8237                                 ip + 5 < end && ip_in_bb (cfg, bblock, ip + 5) &&
8238                                 (ip [5] == CEE_BRTRUE || 
8239                                  ip [5] == CEE_BRTRUE_S ||
8240                                  ip [5] == CEE_BRFALSE ||
8241                                  ip [5] == CEE_BRFALSE_S)) {
8242                                 gboolean is_true = ip [5] == CEE_BRTRUE || ip [5] == CEE_BRTRUE_S;
8243                                 int dreg;
8244                                 MonoBasicBlock *true_bb, *false_bb;
8245
8246                                 ip += 5;
8247
8248                                 if (cfg->verbose_level > 3) {
8249                                         printf ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
8250                                         printf ("<box+brtrue opt>\n");
8251                                 }
8252
8253                                 switch (*ip) {
8254                                 case CEE_BRTRUE_S:
8255                                 case CEE_BRFALSE_S:
8256                                         CHECK_OPSIZE (2);
8257                                         ip++;
8258                                         target = ip + 1 + (signed char)(*ip);
8259                                         ip++;
8260                                         break;
8261                                 case CEE_BRTRUE:
8262                                 case CEE_BRFALSE:
8263                                         CHECK_OPSIZE (5);
8264                                         ip++;
8265                                         target = ip + 4 + (gint)(read32 (ip));
8266                                         ip += 4;
8267                                         break;
8268                                 default:
8269                                         g_assert_not_reached ();
8270                                 }
8271
8272                                 /* 
8273                                  * We need to link both bblocks, since it is needed for handling stack
8274                                  * arguments correctly (See test_0_box_brtrue_opt_regress_81102).
8275                                  * Branching to only one of them would lead to inconsistencies, so
8276                                  * generate an ICONST+BRTRUE, the branch opts will get rid of them.
8277                                  */
8278                                 GET_BBLOCK (cfg, true_bb, target);
8279                                 GET_BBLOCK (cfg, false_bb, ip);
8280
8281                                 mono_link_bblock (cfg, cfg->cbb, true_bb);
8282                                 mono_link_bblock (cfg, cfg->cbb, false_bb);
8283
8284                                 if (sp != stack_start) {
8285                                         handle_stack_args (cfg, stack_start, sp - stack_start);
8286                                         sp = stack_start;
8287                                         CHECK_UNVERIFIABLE (cfg);
8288                                 }
8289
8290                                 if (COMPILE_LLVM (cfg)) {
8291                                         dreg = alloc_ireg (cfg);
8292                                         MONO_EMIT_NEW_ICONST (cfg, dreg, 0);
8293                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, dreg, is_true ? 0 : 1);
8294
8295                                         MONO_EMIT_NEW_BRANCH_BLOCK2 (cfg, OP_IBEQ, true_bb, false_bb);
8296                                 } else {
8297                                         /* The JIT can't eliminate the iconst+compare */
8298                                         MONO_INST_NEW (cfg, ins, OP_BR);
8299                                         ins->inst_target_bb = is_true ? true_bb : false_bb;
8300                                         MONO_ADD_INS (cfg->cbb, ins);
8301                                 }
8302
8303                                 start_new_bblock = 1;
8304                                 break;
8305                         }
8306
8307                         *sp++ = handle_box (cfg, val, klass, context_used);
8308
8309                         CHECK_CFG_EXCEPTION;
8310                         ip += 5;
8311                         inline_costs += 1;
8312                         break;
8313                 }
8314                 case CEE_UNBOX: {
8315                         CHECK_STACK (1);
8316                         --sp;
8317                         CHECK_OPSIZE (5);
8318                         token = read32 (ip + 1);
8319                         klass = mini_get_class (method, token, generic_context);
8320                         CHECK_TYPELOAD (klass);
8321
8322                         mono_save_token_info (cfg, image, token, klass);
8323
8324                         if (cfg->generic_sharing_context)
8325                                 context_used = mono_class_check_context_used (klass);
8326
8327                         if (mono_class_is_nullable (klass)) {
8328                                 MonoInst *val;
8329
8330                                 val = handle_unbox_nullable (cfg, *sp, klass, context_used);
8331                                 EMIT_NEW_VARLOADA (cfg, ins, get_vreg_to_inst (cfg, val->dreg), &val->klass->byval_arg);
8332
8333                                 *sp++= ins;
8334                         } else {
8335                                 ins = handle_unbox (cfg, klass, sp, context_used);
8336                                 *sp++ = ins;
8337                         }
8338                         ip += 5;
8339                         inline_costs += 2;
8340                         break;
8341                 }
8342                 case CEE_LDFLD:
8343                 case CEE_LDFLDA:
8344                 case CEE_STFLD: {
8345                         MonoClassField *field;
8346                         int costs;
8347                         guint foffset;
8348
8349                         if (*ip == CEE_STFLD) {
8350                                 CHECK_STACK (2);
8351                                 sp -= 2;
8352                         } else {
8353                                 CHECK_STACK (1);
8354                                 --sp;
8355                         }
8356                         if (sp [0]->type == STACK_I4 || sp [0]->type == STACK_I8 || sp [0]->type == STACK_R8)
8357                                 UNVERIFIED;
8358                         if (*ip != CEE_LDFLD && sp [0]->type == STACK_VTYPE)
8359                                 UNVERIFIED;
8360                         CHECK_OPSIZE (5);
8361                         token = read32 (ip + 1);
8362                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8363                                 field = mono_method_get_wrapper_data (method, token);
8364                                 klass = field->parent;
8365                         }
8366                         else {
8367                                 field = mono_field_from_token (image, token, &klass, generic_context);
8368                         }
8369                         if (!field)
8370                                 LOAD_ERROR;
8371                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
8372                                 FIELD_ACCESS_FAILURE;
8373                         mono_class_init (klass);
8374
8375                         /* XXX this is technically required but, so far (SL2), no [SecurityCritical] types (not many exists) have
8376                            any visible *instance* field  (in fact there's a single case for a static field in Marshal) XXX
8377                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
8378                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
8379                         */
8380
8381                         foffset = klass->valuetype? field->offset - sizeof (MonoObject): field->offset;
8382                         if (*ip == CEE_STFLD) {
8383                                 if (target_type_is_incompatible (cfg, field->type, sp [1]))
8384                                         UNVERIFIED;
8385                                 if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
8386                                         MonoMethod *stfld_wrapper = mono_marshal_get_stfld_wrapper (field->type); 
8387                                         MonoInst *iargs [5];
8388
8389                                         iargs [0] = sp [0];
8390                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8391                                         EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
8392                                         EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : 
8393                                                     field->offset);
8394                                         iargs [4] = sp [1];
8395
8396                                         if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
8397                                                 costs = inline_method (cfg, stfld_wrapper, mono_method_signature (stfld_wrapper), 
8398                                                                        iargs, ip, cfg->real_offset, dont_inline, TRUE);
8399                                                 CHECK_CFG_EXCEPTION;
8400                                                 g_assert (costs > 0);
8401                                                       
8402                                                 cfg->real_offset += 5;
8403                                                 bblock = cfg->cbb;
8404
8405                                                 inline_costs += costs;
8406                                         } else {
8407                                                 mono_emit_method_call (cfg, stfld_wrapper, iargs, NULL);
8408                                         }
8409                                 } else {
8410                                         MonoInst *store;
8411
8412                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
8413
8414                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, sp [0]->dreg, foffset, sp [1]->dreg);
8415                                         if (sp [0]->opcode != OP_LDADDR)
8416                                                 store->flags |= MONO_INST_FAULT;
8417
8418                                 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)) {
8419                                         /* insert call to write barrier */
8420                                         MonoInst *ptr;
8421                                         int dreg;
8422
8423                                         dreg = alloc_preg (cfg);
8424                                         EMIT_NEW_BIALU_IMM (cfg, ptr, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
8425                                         emit_write_barrier (cfg, ptr, sp [1], -1);
8426                                 }
8427
8428                                         store->flags |= ins_flag;
8429                                 }
8430                                 ins_flag = 0;
8431                                 ip += 5;
8432                                 break;
8433                         }
8434
8435                         if ((klass->marshalbyref && !MONO_CHECK_THIS (sp [0])) || klass->contextbound || klass == mono_defaults.marshalbyrefobject_class) {
8436                                 MonoMethod *wrapper = (*ip == CEE_LDFLDA) ? mono_marshal_get_ldflda_wrapper (field->type) : mono_marshal_get_ldfld_wrapper (field->type); 
8437                                 MonoInst *iargs [4];
8438
8439                                 iargs [0] = sp [0];
8440                                 EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8441                                 EMIT_NEW_FIELDCONST (cfg, iargs [2], field);
8442                                 EMIT_NEW_ICONST (cfg, iargs [3], klass->valuetype ? field->offset - sizeof (MonoObject) : field->offset);
8443                                 if (cfg->opt & MONO_OPT_INLINE || cfg->compile_aot) {
8444                                         costs = inline_method (cfg, wrapper, mono_method_signature (wrapper), 
8445                                                                                    iargs, ip, cfg->real_offset, dont_inline, TRUE);
8446                                         CHECK_CFG_EXCEPTION;
8447                                         bblock = cfg->cbb;
8448                                         g_assert (costs > 0);
8449                                                       
8450                                         cfg->real_offset += 5;
8451
8452                                         *sp++ = iargs [0];
8453
8454                                         inline_costs += costs;
8455                                 } else {
8456                                         ins = mono_emit_method_call (cfg, wrapper, iargs, NULL);
8457                                         *sp++ = ins;
8458                                 }
8459                         } else {
8460                                 if (sp [0]->type == STACK_VTYPE) {
8461                                         MonoInst *var;
8462
8463                                         /* Have to compute the address of the variable */
8464
8465                                         var = get_vreg_to_inst (cfg, sp [0]->dreg);
8466                                         if (!var)
8467                                                 var = mono_compile_create_var_for_vreg (cfg, &klass->byval_arg, OP_LOCAL, sp [0]->dreg);
8468                                         else
8469                                                 g_assert (var->klass == klass);
8470                                         
8471                                         EMIT_NEW_VARLOADA (cfg, ins, var, &var->klass->byval_arg);
8472                                         sp [0] = ins;
8473                                 }
8474
8475                                 if (*ip == CEE_LDFLDA) {
8476                                         if (sp [0]->type == STACK_OBJ) {
8477                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, sp [0]->dreg, 0);
8478                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "NullReferenceException");
8479                                         }
8480
8481                                         dreg = alloc_preg (cfg);
8482
8483                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, dreg, sp [0]->dreg, foffset);
8484                                         ins->klass = mono_class_from_mono_type (field->type);
8485                                         ins->type = STACK_MP;
8486                                         *sp++ = ins;
8487                                 } else {
8488                                         MonoInst *load;
8489
8490                                         MONO_EMIT_NULL_CHECK (cfg, sp [0]->dreg);
8491
8492                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, sp [0]->dreg, foffset);
8493                                         load->flags |= ins_flag;
8494                                         if (sp [0]->opcode != OP_LDADDR)
8495                                                 load->flags |= MONO_INST_FAULT;
8496                                         *sp++ = load;
8497                                 }
8498                         }
8499                         ins_flag = 0;
8500                         ip += 5;
8501                         break;
8502                 }
8503                 case CEE_LDSFLD:
8504                 case CEE_LDSFLDA:
8505                 case CEE_STSFLD: {
8506                         MonoClassField *field;
8507                         gpointer addr = NULL;
8508                         gboolean is_special_static;
8509
8510                         CHECK_OPSIZE (5);
8511                         token = read32 (ip + 1);
8512
8513                         if (method->wrapper_type != MONO_WRAPPER_NONE) {
8514                                 field = mono_method_get_wrapper_data (method, token);
8515                                 klass = field->parent;
8516                         }
8517                         else
8518                                 field = mono_field_from_token (image, token, &klass, generic_context);
8519                         if (!field)
8520                                 LOAD_ERROR;
8521                         mono_class_init (klass);
8522                         if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_field (method, field))
8523                                 FIELD_ACCESS_FAILURE;
8524
8525                         /* if the class is Critical then transparent code cannot access it's fields */
8526                         if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR)
8527                                 ensure_method_is_allowed_to_access_field (cfg, method, field, bblock, ip);
8528
8529                         /*
8530                          * We can only support shared generic static
8531                          * field access on architectures where the
8532                          * trampoline code has been extended to handle
8533                          * the generic class init.
8534                          */
8535 #ifndef MONO_ARCH_VTABLE_REG
8536                         GENERIC_SHARING_FAILURE (*ip);
8537 #endif
8538
8539                         if (cfg->generic_sharing_context)
8540                                 context_used = mono_class_check_context_used (klass);
8541
8542                         g_assert (!(field->type->attrs & FIELD_ATTRIBUTE_LITERAL));
8543
8544                         /* The special_static_fields field is init'd in mono_class_vtable, so it needs
8545                          * to be called here.
8546                          */
8547                         if (!context_used && !(cfg->opt & MONO_OPT_SHARED)) {
8548                                 mono_class_vtable (cfg->domain, klass);
8549                                 CHECK_TYPELOAD (klass);
8550                         }
8551                         mono_domain_lock (cfg->domain);
8552                         if (cfg->domain->special_static_fields)
8553                                 addr = g_hash_table_lookup (cfg->domain->special_static_fields, field);
8554                         mono_domain_unlock (cfg->domain);
8555
8556                         is_special_static = mono_class_field_is_special_static (field);
8557
8558                         /* Generate IR to compute the field address */
8559                         if (is_special_static && ((gsize)addr & 0x80000000) == 0 && mono_get_thread_intrinsic (cfg) && !(cfg->opt & MONO_OPT_SHARED) && !context_used) {
8560                                 /*
8561                                  * Fast access to TLS data
8562                                  * Inline version of get_thread_static_data () in
8563                                  * threads.c.
8564                                  */
8565                                 guint32 offset;
8566                                 int idx, static_data_reg, array_reg, dreg;
8567                                 MonoInst *thread_ins;
8568
8569                                 // offset &= 0x7fffffff;
8570                                 // idx = (offset >> 24) - 1;
8571                                 //      return ((char*) thread->static_data [idx]) + (offset & 0xffffff);
8572
8573                                 thread_ins = mono_get_thread_intrinsic (cfg);
8574                                 MONO_ADD_INS (cfg->cbb, thread_ins);
8575                                 static_data_reg = alloc_ireg (cfg);
8576                                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, static_data_reg, thread_ins->dreg, G_STRUCT_OFFSET (MonoInternalThread, static_data));
8577
8578                                 if (cfg->compile_aot) {
8579                                         int offset_reg, offset2_reg, idx_reg;
8580
8581                                         /* For TLS variables, this will return the TLS offset */
8582                                         EMIT_NEW_SFLDACONST (cfg, ins, field);
8583                                         offset_reg = ins->dreg;
8584                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset_reg, offset_reg, 0x7fffffff);
8585                                         idx_reg = alloc_ireg (cfg);
8586                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHR_IMM, idx_reg, offset_reg, 24);
8587                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISUB_IMM, idx_reg, idx_reg, 1);
8588                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ISHL_IMM, idx_reg, idx_reg, sizeof (gpointer) == 8 ? 3 : 2);
8589                                         MONO_EMIT_NEW_BIALU (cfg, OP_PADD, static_data_reg, static_data_reg, idx_reg);
8590                                         array_reg = alloc_ireg (cfg);
8591                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, 0);
8592                                         offset2_reg = alloc_ireg (cfg);
8593                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, offset2_reg, offset_reg, 0xffffff);
8594                                         dreg = alloc_ireg (cfg);
8595                                         EMIT_NEW_BIALU (cfg, ins, OP_PADD, dreg, array_reg, offset2_reg);
8596                                 } else {
8597                                         offset = (gsize)addr & 0x7fffffff;
8598                                         idx = (offset >> 24) - 1;
8599
8600                                         array_reg = alloc_ireg (cfg);
8601                                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, array_reg, static_data_reg, idx * sizeof (gpointer));
8602                                         dreg = alloc_ireg (cfg);
8603                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_ADD_IMM, dreg, array_reg, (offset & 0xffffff));
8604                                 }
8605                         } else if ((cfg->opt & MONO_OPT_SHARED) ||
8606                                         (cfg->compile_aot && is_special_static) ||
8607                                         (context_used && is_special_static)) {
8608                                 MonoInst *iargs [2];
8609
8610                                 g_assert (field->parent);
8611                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8612                                 if (context_used) {
8613                                         iargs [1] = emit_get_rgctx_field (cfg, context_used,
8614                                                 field, MONO_RGCTX_INFO_CLASS_FIELD);
8615                                 } else {
8616                                         EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
8617                                 }
8618                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
8619                         } else if (context_used) {
8620                                 MonoInst *static_data;
8621
8622                                 /*
8623                                 g_print ("sharing static field access in %s.%s.%s - depth %d offset %d\n",
8624                                         method->klass->name_space, method->klass->name, method->name,
8625                                         depth, field->offset);
8626                                 */
8627
8628                                 if (mono_class_needs_cctor_run (klass, method))
8629                                         emit_generic_class_init (cfg, klass);
8630
8631                                 /*
8632                                  * The pointer we're computing here is
8633                                  *
8634                                  *   super_info.static_data + field->offset
8635                                  */
8636                                 static_data = emit_get_rgctx_klass (cfg, context_used,
8637                                         klass, MONO_RGCTX_INFO_STATIC_DATA);
8638
8639                                 if (field->offset == 0) {
8640                                         ins = static_data;
8641                                 } else {
8642                                         int addr_reg = mono_alloc_preg (cfg);
8643                                         EMIT_NEW_BIALU_IMM (cfg, ins, OP_PADD_IMM, addr_reg, static_data->dreg, field->offset);
8644                                 }
8645                                 } else if ((cfg->opt & MONO_OPT_SHARED) || (cfg->compile_aot && addr)) {
8646                                 MonoInst *iargs [2];
8647
8648                                 g_assert (field->parent);
8649                                 EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8650                                 EMIT_NEW_FIELDCONST (cfg, iargs [1], field);
8651                                 ins = mono_emit_jit_icall (cfg, mono_class_static_field_address, iargs);
8652                         } else {
8653                                 MonoVTable *vtable = mono_class_vtable (cfg->domain, klass);
8654
8655                                 CHECK_TYPELOAD (klass);
8656                                 if (!addr) {
8657                                         if (mini_field_access_needs_cctor_run (cfg, method, vtable) && !(g_slist_find (class_inits, vtable))) {
8658                                                 mono_emit_abs_call (cfg, MONO_PATCH_INFO_CLASS_INIT, vtable->klass, helper_sig_class_init_trampoline, NULL);
8659                                                 if (cfg->verbose_level > 2)
8660                                                         printf ("class %s.%s needs init call for %s\n", klass->name_space, klass->name, mono_field_get_name (field));
8661                                                 class_inits = g_slist_prepend (class_inits, vtable);
8662                                         } else {
8663                                                 if (cfg->run_cctors) {
8664                                                         MonoException *ex;
8665                                                         /* This makes so that inline cannot trigger */
8666                                                         /* .cctors: too many apps depend on them */
8667                                                         /* running with a specific order... */
8668                                                         if (! vtable->initialized)
8669                                                                 INLINE_FAILURE;
8670                                                         ex = mono_runtime_class_init_full (vtable, FALSE);
8671                                                         if (ex) {
8672                                                                 set_exception_object (cfg, ex);
8673                                                                 goto exception_exit;
8674                                                         }
8675                                                 }
8676                                         }
8677                                         addr = (char*)vtable->data + field->offset;
8678
8679                                         if (cfg->compile_aot)
8680                                                 EMIT_NEW_SFLDACONST (cfg, ins, field);
8681                                         else
8682                                                 EMIT_NEW_PCONST (cfg, ins, addr);
8683                                 } else {
8684                                         MonoInst *iargs [1];
8685                                         EMIT_NEW_ICONST (cfg, iargs [0], GPOINTER_TO_UINT (addr));
8686                                         ins = mono_emit_jit_icall (cfg, mono_get_special_static_data, iargs);
8687                                 }
8688                         }
8689
8690                         /* Generate IR to do the actual load/store operation */
8691
8692                         if (*ip == CEE_LDSFLDA) {
8693                                 ins->klass = mono_class_from_mono_type (field->type);
8694                                 ins->type = STACK_PTR;
8695                                 *sp++ = ins;
8696                         } else if (*ip == CEE_STSFLD) {
8697                                 MonoInst *store;
8698                                 CHECK_STACK (1);
8699                                 sp--;
8700
8701                                 EMIT_NEW_STORE_MEMBASE_TYPE (cfg, store, field->type, ins->dreg, 0, sp [0]->dreg);
8702                                 store->flags |= ins_flag;
8703                         } else {
8704                                 gboolean is_const = FALSE;
8705                                 MonoVTable *vtable = NULL;
8706
8707                                 if (!context_used) {
8708                                         vtable = mono_class_vtable (cfg->domain, klass);
8709                                         CHECK_TYPELOAD (klass);
8710                                 }
8711                                 if (!context_used && !((cfg->opt & MONO_OPT_SHARED) || cfg->compile_aot) && 
8712                                     vtable->initialized && (field->type->attrs & FIELD_ATTRIBUTE_INIT_ONLY)) {
8713                                         gpointer addr = (char*)vtable->data + field->offset;
8714                                         int ro_type = field->type->type;
8715                                         if (ro_type == MONO_TYPE_VALUETYPE && field->type->data.klass->enumtype) {
8716                                                 ro_type = mono_class_enum_basetype (field->type->data.klass)->type;
8717                                         }
8718                                         /* printf ("RO-FIELD %s.%s:%s\n", klass->name_space, klass->name, mono_field_get_name (field));*/
8719                                         is_const = TRUE;
8720                                         switch (ro_type) {
8721                                         case MONO_TYPE_BOOLEAN:
8722                                         case MONO_TYPE_U1:
8723                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint8 *)addr));
8724                                                 sp++;
8725                                                 break;
8726                                         case MONO_TYPE_I1:
8727                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint8 *)addr));
8728                                                 sp++;
8729                                                 break;                                          
8730                                         case MONO_TYPE_CHAR:
8731                                         case MONO_TYPE_U2:
8732                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint16 *)addr));
8733                                                 sp++;
8734                                                 break;
8735                                         case MONO_TYPE_I2:
8736                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint16 *)addr));
8737                                                 sp++;
8738                                                 break;
8739                                                 break;
8740                                         case MONO_TYPE_I4:
8741                                                 EMIT_NEW_ICONST (cfg, *sp, *((gint32 *)addr));
8742                                                 sp++;
8743                                                 break;                                          
8744                                         case MONO_TYPE_U4:
8745                                                 EMIT_NEW_ICONST (cfg, *sp, *((guint32 *)addr));
8746                                                 sp++;
8747                                                 break;
8748                                         case MONO_TYPE_I:
8749                                         case MONO_TYPE_U:
8750                                         case MONO_TYPE_PTR:
8751                                         case MONO_TYPE_FNPTR:
8752                                                 EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8753                                                 type_to_eval_stack_type ((cfg), field->type, *sp);
8754                                                 sp++;
8755                                                 break;
8756                                         case MONO_TYPE_STRING:
8757                                         case MONO_TYPE_OBJECT:
8758                                         case MONO_TYPE_CLASS:
8759                                         case MONO_TYPE_SZARRAY:
8760                                         case MONO_TYPE_ARRAY:
8761                                                 if (!mono_gc_is_moving ()) {
8762                                                         EMIT_NEW_PCONST (cfg, *sp, *((gpointer *)addr));
8763                                                         type_to_eval_stack_type ((cfg), field->type, *sp);
8764                                                         sp++;
8765                                                 } else {
8766                                                         is_const = FALSE;
8767                                                 }
8768                                                 break;
8769                                         case MONO_TYPE_I8:
8770                                         case MONO_TYPE_U8:
8771                                                 EMIT_NEW_I8CONST (cfg, *sp, *((gint64 *)addr));
8772                                                 sp++;
8773                                                 break;
8774                                         case MONO_TYPE_R4:
8775                                         case MONO_TYPE_R8:
8776                                         case MONO_TYPE_VALUETYPE:
8777                                         default:
8778                                                 is_const = FALSE;
8779                                                 break;
8780                                         }
8781                                 }
8782
8783                                 if (!is_const) {
8784                                         MonoInst *load;
8785
8786                                         CHECK_STACK_OVF (1);
8787
8788                                         EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, load, field->type, ins->dreg, 0);
8789                                         load->flags |= ins_flag;
8790                                         ins_flag = 0;
8791                                         *sp++ = load;
8792                                 }
8793                         }
8794                         ins_flag = 0;
8795                         ip += 5;
8796                         break;
8797                 }
8798                 case CEE_STOBJ:
8799                         CHECK_STACK (2);
8800                         sp -= 2;
8801                         CHECK_OPSIZE (5);
8802                         token = read32 (ip + 1);
8803                         klass = mini_get_class (method, token, generic_context);
8804                         CHECK_TYPELOAD (klass);
8805                         /* FIXME: should check item at sp [1] is compatible with the type of the store. */
8806                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, sp [0]->dreg, 0, sp [1]->dreg);
8807                         if (cfg->gen_write_barriers && cfg->method->wrapper_type != MONO_WRAPPER_WRITE_BARRIER &&
8808                                         generic_class_is_reference_type (cfg, klass)) {
8809                                 /* insert call to write barrier */
8810                                 emit_write_barrier (cfg, sp [0], sp [1], -1);
8811                         }
8812                         ins_flag = 0;
8813                         ip += 5;
8814                         inline_costs += 1;
8815                         break;
8816
8817                         /*
8818                          * Array opcodes
8819                          */
8820                 case CEE_NEWARR: {
8821                         MonoInst *len_ins;
8822                         const char *data_ptr;
8823                         int data_size = 0;
8824                         guint32 field_token;
8825
8826                         CHECK_STACK (1);
8827                         --sp;
8828
8829                         CHECK_OPSIZE (5);
8830                         token = read32 (ip + 1);
8831
8832                         klass = mini_get_class (method, token, generic_context);
8833                         CHECK_TYPELOAD (klass);
8834
8835                         if (cfg->generic_sharing_context)
8836                                 context_used = mono_class_check_context_used (klass);
8837
8838                         if (sp [0]->type == STACK_I8 || (SIZEOF_VOID_P == 8 && sp [0]->type == STACK_PTR)) {
8839                                 MONO_INST_NEW (cfg, ins, OP_LCONV_TO_I4);
8840                                 ins->sreg1 = sp [0]->dreg;
8841                                 ins->type = STACK_I4;
8842                                 ins->dreg = alloc_ireg (cfg);
8843                                 MONO_ADD_INS (cfg->cbb, ins);
8844                                 *sp = mono_decompose_opcode (cfg, ins);
8845                         }
8846
8847                         if (context_used) {
8848                                 MonoInst *args [3];
8849                                 MonoClass *array_class = mono_array_class_get (klass, 1);
8850                                 /* FIXME: we cannot get a managed
8851                                    allocator because we can't get the
8852                                    open generic class's vtable.  We
8853                                    have the same problem in
8854                                    handle_alloc().  This
8855                                    needs to be solved so that we can
8856                                    have managed allocs of shared
8857                                    generic classes. */
8858                                 /*
8859                                 MonoVTable *array_class_vtable = mono_class_vtable (cfg->domain, array_class);
8860                                 MonoMethod *managed_alloc = mono_gc_get_managed_array_allocator (array_class_vtable, 1);
8861                                 */
8862                                 MonoMethod *managed_alloc = NULL;
8863
8864                                 /* FIXME: Decompose later to help abcrem */
8865
8866                                 /* vtable */
8867                                 args [0] = emit_get_rgctx_klass (cfg, context_used,
8868                                         array_class, MONO_RGCTX_INFO_VTABLE);
8869                                 /* array len */
8870                                 args [1] = sp [0];
8871
8872                                 if (managed_alloc)
8873                                         ins = mono_emit_method_call (cfg, managed_alloc, args, NULL);
8874                                 else
8875                                         ins = mono_emit_jit_icall (cfg, mono_array_new_specific, args);
8876                         } else {
8877                                 if (cfg->opt & MONO_OPT_SHARED) {
8878                                         /* Decompose now to avoid problems with references to the domainvar */
8879                                         MonoInst *iargs [3];
8880
8881                                         EMIT_NEW_DOMAINCONST (cfg, iargs [0]);
8882                                         EMIT_NEW_CLASSCONST (cfg, iargs [1], klass);
8883                                         iargs [2] = sp [0];
8884
8885                                         ins = mono_emit_jit_icall (cfg, mono_array_new, iargs);
8886                                 } else {
8887                                         /* Decompose later since it is needed by abcrem */
8888                                         MonoClass *array_type = mono_array_class_get (klass, 1);
8889                                         mono_class_vtable (cfg->domain, array_type);
8890                                         CHECK_TYPELOAD (array_type);
8891
8892                                         MONO_INST_NEW (cfg, ins, OP_NEWARR);
8893                                         ins->dreg = alloc_preg (cfg);
8894                                         ins->sreg1 = sp [0]->dreg;
8895                                         ins->inst_newa_class = klass;
8896                                         ins->type = STACK_OBJ;
8897                                         ins->klass = klass;
8898                                         MONO_ADD_INS (cfg->cbb, ins);
8899                                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
8900                                         cfg->cbb->has_array_access = TRUE;
8901
8902                                         /* Needed so mono_emit_load_get_addr () gets called */
8903                                         mono_get_got_var (cfg);
8904                                 }
8905                         }
8906
8907                         len_ins = sp [0];
8908                         ip += 5;
8909                         *sp++ = ins;
8910                         inline_costs += 1;
8911
8912                         /* 
8913                          * we inline/optimize the initialization sequence if possible.
8914                          * we should also allocate the array as not cleared, since we spend as much time clearing to 0 as initializing
8915                          * for small sizes open code the memcpy
8916                          * ensure the rva field is big enough
8917                          */
8918                         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))) {
8919                                 MonoMethod *memcpy_method = get_memcpy_method ();
8920                                 MonoInst *iargs [3];
8921                                 int add_reg = alloc_preg (cfg);
8922
8923                                 EMIT_NEW_BIALU_IMM (cfg, iargs [0], OP_PADD_IMM, add_reg, ins->dreg, G_STRUCT_OFFSET (MonoArray, vector));
8924                                 if (cfg->compile_aot) {
8925                                         EMIT_NEW_AOTCONST_TOKEN (cfg, iargs [1], MONO_PATCH_INFO_RVA, method->klass->image, GPOINTER_TO_UINT(field_token), STACK_PTR, NULL);
8926                                 } else {
8927                                         EMIT_NEW_PCONST (cfg, iargs [1], (char*)data_ptr);
8928                                 }
8929                                 EMIT_NEW_ICONST (cfg, iargs [2], data_size);
8930                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
8931                                 ip += 11;
8932                         }
8933
8934                         break;
8935                 }
8936                 case CEE_LDLEN:
8937                         CHECK_STACK (1);
8938                         --sp;
8939                         if (sp [0]->type != STACK_OBJ)
8940                                 UNVERIFIED;
8941
8942                         dreg = alloc_preg (cfg);
8943                         MONO_INST_NEW (cfg, ins, OP_LDLEN);
8944                         ins->dreg = alloc_preg (cfg);
8945                         ins->sreg1 = sp [0]->dreg;
8946                         ins->type = STACK_I4;
8947                         /* This flag will be inherited by the decomposition */
8948                         ins->flags |= MONO_INST_FAULT;
8949                         MONO_ADD_INS (cfg->cbb, ins);
8950                         cfg->flags |= MONO_CFG_HAS_ARRAY_ACCESS;
8951                         cfg->cbb->has_array_access = TRUE;
8952                         ip ++;
8953                         *sp++ = ins;
8954                         break;
8955                 case CEE_LDELEMA:
8956                         CHECK_STACK (2);
8957                         sp -= 2;
8958                         CHECK_OPSIZE (5);
8959                         if (sp [0]->type != STACK_OBJ)
8960                                 UNVERIFIED;
8961
8962                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
8963
8964                         klass = mini_get_class (method, read32 (ip + 1), generic_context);
8965                         CHECK_TYPELOAD (klass);
8966                         /* we need to make sure that this array is exactly the type it needs
8967                          * to be for correctness. the wrappers are lax with their usage
8968                          * so we need to ignore them here
8969                          */
8970                         if (!klass->valuetype && method->wrapper_type == MONO_WRAPPER_NONE && !readonly) {
8971                                 MonoClass *array_class = mono_array_class_get (klass, 1);
8972                                 mini_emit_check_array_type (cfg, sp [0], array_class);
8973                                 CHECK_TYPELOAD (array_class);
8974                         }
8975
8976                         readonly = FALSE;
8977                         ins = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
8978                         *sp++ = ins;
8979                         ip += 5;
8980                         break;
8981                 case CEE_LDELEM:
8982                 case CEE_LDELEM_I1:
8983                 case CEE_LDELEM_U1:
8984                 case CEE_LDELEM_I2:
8985                 case CEE_LDELEM_U2:
8986                 case CEE_LDELEM_I4:
8987                 case CEE_LDELEM_U4:
8988                 case CEE_LDELEM_I8:
8989                 case CEE_LDELEM_I:
8990                 case CEE_LDELEM_R4:
8991                 case CEE_LDELEM_R8:
8992                 case CEE_LDELEM_REF: {
8993                         MonoInst *addr;
8994
8995                         CHECK_STACK (2);
8996                         sp -= 2;
8997
8998                         if (*ip == CEE_LDELEM) {
8999                                 CHECK_OPSIZE (5);
9000                                 token = read32 (ip + 1);
9001                                 klass = mini_get_class (method, token, generic_context);
9002                                 CHECK_TYPELOAD (klass);
9003                                 mono_class_init (klass);
9004                         }
9005                         else
9006                                 klass = array_access_to_klass (*ip);
9007
9008                         if (sp [0]->type != STACK_OBJ)
9009                                 UNVERIFIED;
9010
9011                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
9012
9013                         if (sp [1]->opcode == OP_ICONST) {
9014                                 int array_reg = sp [0]->dreg;
9015                                 int index_reg = sp [1]->dreg;
9016                                 int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
9017
9018                                 MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
9019                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset);
9020                         } else {
9021                                 addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
9022                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0);
9023                         }
9024                         *sp++ = ins;
9025                         if (*ip == CEE_LDELEM)
9026                                 ip += 5;
9027                         else
9028                                 ++ip;
9029                         break;
9030                 }
9031                 case CEE_STELEM_I:
9032                 case CEE_STELEM_I1:
9033                 case CEE_STELEM_I2:
9034                 case CEE_STELEM_I4:
9035                 case CEE_STELEM_I8:
9036                 case CEE_STELEM_R4:
9037                 case CEE_STELEM_R8:
9038                 case CEE_STELEM_REF:
9039                 case CEE_STELEM: {
9040                         MonoInst *addr;
9041
9042                         CHECK_STACK (3);
9043                         sp -= 3;
9044
9045                         cfg->flags |= MONO_CFG_HAS_LDELEMA;
9046
9047                         if (*ip == CEE_STELEM) {
9048                                 CHECK_OPSIZE (5);
9049                                 token = read32 (ip + 1);
9050                                 klass = mini_get_class (method, token, generic_context);
9051                                 CHECK_TYPELOAD (klass);
9052                                 mono_class_init (klass);
9053                         }
9054                         else
9055                                 klass = array_access_to_klass (*ip);
9056
9057                         if (sp [0]->type != STACK_OBJ)
9058                                 UNVERIFIED;
9059
9060                         /* storing a NULL doesn't need any of the complex checks in stelemref */
9061                         if (generic_class_is_reference_type (cfg, klass) &&
9062                                 !(sp [2]->opcode == OP_PCONST && sp [2]->inst_p0 == NULL)) {
9063                                 MonoClass *obj_array = mono_array_class_get_cached (mono_defaults.object_class, 1);
9064                                 MonoMethod *helper = mono_marshal_get_virtual_stelemref (obj_array);
9065                                 MonoInst *iargs [3];
9066
9067                                 if (!helper->slot)
9068                                         mono_class_setup_vtable (obj_array);
9069                                 g_assert (helper->slot);
9070
9071                                 if (sp [0]->type != STACK_OBJ)
9072                                         UNVERIFIED;
9073                                 if (sp [2]->type != STACK_OBJ)
9074                                         UNVERIFIED;
9075
9076                                 iargs [2] = sp [2];
9077                                 iargs [1] = sp [1];
9078                                 iargs [0] = sp [0];
9079
9080                                 mono_emit_method_call (cfg, helper, iargs, sp [0]);
9081                         } else {
9082                                 if (sp [1]->opcode == OP_ICONST) {
9083                                         int array_reg = sp [0]->dreg;
9084                                         int index_reg = sp [1]->dreg;
9085                                         int offset = (mono_class_array_element_size (klass) * sp [1]->inst_c0) + G_STRUCT_OFFSET (MonoArray, vector);
9086
9087                                         MONO_EMIT_BOUNDS_CHECK (cfg, array_reg, MonoArray, max_length, index_reg);
9088                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, array_reg, offset, sp [2]->dreg);
9089                                 } else {
9090                                         addr = mini_emit_ldelema_1_ins (cfg, klass, sp [0], sp [1], TRUE);
9091                                         EMIT_NEW_STORE_MEMBASE_TYPE (cfg, ins, &klass->byval_arg, addr->dreg, 0, sp [2]->dreg);
9092                                 }
9093                         }
9094
9095                         if (*ip == CEE_STELEM)
9096                                 ip += 5;
9097                         else
9098                                 ++ip;
9099                         inline_costs += 1;
9100                         break;
9101                 }
9102                 case CEE_CKFINITE: {
9103                         CHECK_STACK (1);
9104                         --sp;
9105
9106                         MONO_INST_NEW (cfg, ins, OP_CKFINITE);
9107                         ins->sreg1 = sp [0]->dreg;
9108                         ins->dreg = alloc_freg (cfg);
9109                         ins->type = STACK_R8;
9110                         MONO_ADD_INS (bblock, ins);
9111
9112                         *sp++ = mono_decompose_opcode (cfg, ins);
9113
9114                         ++ip;
9115                         break;
9116                 }
9117                 case CEE_REFANYVAL: {
9118                         MonoInst *src_var, *src;
9119
9120                         int klass_reg = alloc_preg (cfg);
9121                         int dreg = alloc_preg (cfg);
9122
9123                         CHECK_STACK (1);
9124                         MONO_INST_NEW (cfg, ins, *ip);
9125                         --sp;
9126                         CHECK_OPSIZE (5);
9127                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
9128                         CHECK_TYPELOAD (klass);
9129                         mono_class_init (klass);
9130
9131                         if (cfg->generic_sharing_context)
9132                                 context_used = mono_class_check_context_used (klass);
9133
9134                         // FIXME:
9135                         src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9136                         if (!src_var)
9137                                 src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
9138                         EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
9139                         MONO_EMIT_NEW_LOAD_MEMBASE (cfg, klass_reg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass));
9140
9141                         if (context_used) {
9142                                 MonoInst *klass_ins;
9143
9144                                 klass_ins = emit_get_rgctx_klass (cfg, context_used,
9145                                                 klass, MONO_RGCTX_INFO_KLASS);
9146
9147                                 // FIXME:
9148                                 MONO_EMIT_NEW_BIALU (cfg, OP_COMPARE, -1, klass_reg, klass_ins->dreg);
9149                                 MONO_EMIT_NEW_COND_EXC (cfg, NE_UN, "InvalidCastException");
9150                         } else {
9151                                 mini_emit_class_check (cfg, klass_reg, klass);
9152                         }
9153                         EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, value));
9154                         ins->type = STACK_MP;
9155                         *sp++ = ins;
9156                         ip += 5;
9157                         break;
9158                 }
9159                 case CEE_MKREFANY: {
9160                         MonoInst *loc, *addr;
9161
9162                         CHECK_STACK (1);
9163                         MONO_INST_NEW (cfg, ins, *ip);
9164                         --sp;
9165                         CHECK_OPSIZE (5);
9166                         klass = mono_class_get_full (image, read32 (ip + 1), generic_context);
9167                         CHECK_TYPELOAD (klass);
9168                         mono_class_init (klass);
9169
9170                         if (cfg->generic_sharing_context)
9171                                 context_used = mono_class_check_context_used (klass);
9172
9173                         loc = mono_compile_create_var (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL);
9174                         EMIT_NEW_TEMPLOADA (cfg, addr, loc->inst_c0);
9175
9176                         if (context_used) {
9177                                 MonoInst *const_ins;
9178                                 int type_reg = alloc_preg (cfg);
9179
9180                                 const_ins = emit_get_rgctx_klass (cfg, context_used, klass, MONO_RGCTX_INFO_KLASS);
9181                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_ins->dreg);
9182                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_ins->dreg, G_STRUCT_OFFSET (MonoClass, byval_arg));
9183                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
9184                         } else if (cfg->compile_aot) {
9185                                 int const_reg = alloc_preg (cfg);
9186                                 int type_reg = alloc_preg (cfg);
9187
9188                                 MONO_EMIT_NEW_CLASSCONST (cfg, const_reg, klass);
9189                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), const_reg);
9190                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ADD_IMM, type_reg, const_reg, G_STRUCT_OFFSET (MonoClass, byval_arg));
9191                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), type_reg);
9192                         } else {
9193                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, type), &klass->byval_arg);
9194                                 MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STOREP_MEMBASE_IMM, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, klass), klass);
9195                         }
9196                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREP_MEMBASE_REG, addr->dreg, G_STRUCT_OFFSET (MonoTypedRef, value), sp [0]->dreg);
9197
9198                         EMIT_NEW_TEMPLOAD (cfg, ins, loc->inst_c0);
9199                         ins->type = STACK_VTYPE;
9200                         ins->klass = mono_defaults.typed_reference_class;
9201                         *sp++ = ins;
9202                         ip += 5;
9203                         break;
9204                 }
9205                 case CEE_LDTOKEN: {
9206                         gpointer handle;
9207                         MonoClass *handle_class;
9208
9209                         CHECK_STACK_OVF (1);
9210
9211                         CHECK_OPSIZE (5);
9212                         n = read32 (ip + 1);
9213
9214                         if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD ||
9215                                         method->wrapper_type == MONO_WRAPPER_SYNCHRONIZED) {
9216                                 handle = mono_method_get_wrapper_data (method, n);
9217                                 handle_class = mono_method_get_wrapper_data (method, n + 1);
9218                                 if (handle_class == mono_defaults.typehandle_class)
9219                                         handle = &((MonoClass*)handle)->byval_arg;
9220                         }
9221                         else {
9222                                 handle = mono_ldtoken (image, n, &handle_class, generic_context);
9223                         }
9224                         if (!handle)
9225                                 LOAD_ERROR;
9226                         mono_class_init (handle_class);
9227                         if (cfg->generic_sharing_context) {
9228                                 if (mono_metadata_token_table (n) == MONO_TABLE_TYPEDEF ||
9229                                                 mono_metadata_token_table (n) == MONO_TABLE_TYPEREF) {
9230                                         /* This case handles ldtoken
9231                                            of an open type, like for
9232                                            typeof(Gen<>). */
9233                                         context_used = 0;
9234                                 } else if (handle_class == mono_defaults.typehandle_class) {
9235                                         /* If we get a MONO_TYPE_CLASS
9236                                            then we need to provide the
9237                                            open type, not an
9238                                            instantiation of it. */
9239                                         if (mono_type_get_type (handle) == MONO_TYPE_CLASS)
9240                                                 context_used = 0;
9241                                         else
9242                                                 context_used = mono_class_check_context_used (mono_class_from_mono_type (handle));
9243                                 } else if (handle_class == mono_defaults.fieldhandle_class)
9244                                         context_used = mono_class_check_context_used (((MonoClassField*)handle)->parent);
9245                                 else if (handle_class == mono_defaults.methodhandle_class)
9246                                         context_used = mono_method_check_context_used (handle);
9247                                 else
9248                                         g_assert_not_reached ();
9249                         }
9250
9251                         if ((cfg->opt & MONO_OPT_SHARED) &&
9252                                         method->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD &&
9253                                         method->wrapper_type != MONO_WRAPPER_SYNCHRONIZED) {
9254                                 MonoInst *addr, *vtvar, *iargs [3];
9255                                 int method_context_used;
9256
9257                                 if (cfg->generic_sharing_context)
9258                                         method_context_used = mono_method_check_context_used (method);
9259                                 else
9260                                         method_context_used = 0;
9261
9262                                 vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL); 
9263
9264                                 EMIT_NEW_IMAGECONST (cfg, iargs [0], image);
9265                                 EMIT_NEW_ICONST (cfg, iargs [1], n);
9266                                 if (method_context_used) {
9267                                         iargs [2] = emit_get_rgctx_method (cfg, method_context_used,
9268                                                 method, MONO_RGCTX_INFO_METHOD);
9269                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper_generic_shared, iargs);
9270                                 } else {
9271                                         EMIT_NEW_PCONST (cfg, iargs [2], generic_context);
9272                                         ins = mono_emit_jit_icall (cfg, mono_ldtoken_wrapper, iargs);
9273                                 }
9274                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9275
9276                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
9277
9278                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9279                         } else {
9280                                 if ((ip + 5 < end) && ip_in_bb (cfg, bblock, ip + 5) && 
9281                                         ((ip [5] == CEE_CALL) || (ip [5] == CEE_CALLVIRT)) && 
9282                                         (cmethod = mini_get_method (cfg, method, read32 (ip + 6), NULL, generic_context)) &&
9283                                         (cmethod->klass == mono_defaults.monotype_class->parent) &&
9284                                         (strcmp (cmethod->name, "GetTypeFromHandle") == 0)) {
9285                                         MonoClass *tclass = mono_class_from_mono_type (handle);
9286
9287                                         mono_class_init (tclass);
9288                                         if (context_used) {
9289                                                 ins = emit_get_rgctx_klass (cfg, context_used,
9290                                                         tclass, MONO_RGCTX_INFO_REFLECTION_TYPE);
9291                                         } else if (cfg->compile_aot) {
9292                                                 if (method->wrapper_type) {
9293                                                         if (mono_class_get (tclass->image, tclass->type_token) == tclass && !generic_context) {
9294                                                                 /* Special case for static synchronized wrappers */
9295                                                                 EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, tclass->image, tclass->type_token, generic_context);
9296                                                         } else {
9297                                                                 /* FIXME: n is not a normal token */
9298                                                                 cfg->disable_aot = TRUE;
9299                                                                 EMIT_NEW_PCONST (cfg, ins, NULL);
9300                                                         }
9301                                                 } else {
9302                                                         EMIT_NEW_TYPE_FROM_HANDLE_CONST (cfg, ins, image, n, generic_context);
9303                                                 }
9304                                         } else {
9305                                                 EMIT_NEW_PCONST (cfg, ins, mono_type_get_object (cfg->domain, handle));
9306                                         }
9307                                         ins->type = STACK_OBJ;
9308                                         ins->klass = cmethod->klass;
9309                                         ip += 5;
9310                                 } else {
9311                                         MonoInst *addr, *vtvar;
9312
9313                                         vtvar = mono_compile_create_var (cfg, &handle_class->byval_arg, OP_LOCAL);
9314
9315                                         if (context_used) {
9316                                                 if (handle_class == mono_defaults.typehandle_class) {
9317                                                         ins = emit_get_rgctx_klass (cfg, context_used,
9318                                                                         mono_class_from_mono_type (handle),
9319                                                                         MONO_RGCTX_INFO_TYPE);
9320                                                 } else if (handle_class == mono_defaults.methodhandle_class) {
9321                                                         ins = emit_get_rgctx_method (cfg, context_used,
9322                                                                         handle, MONO_RGCTX_INFO_METHOD);
9323                                                 } else if (handle_class == mono_defaults.fieldhandle_class) {
9324                                                         ins = emit_get_rgctx_field (cfg, context_used,
9325                                                                         handle, MONO_RGCTX_INFO_CLASS_FIELD);
9326                                                 } else {
9327                                                         g_assert_not_reached ();
9328                                                 }
9329                                         } else if (cfg->compile_aot) {
9330                                                 EMIT_NEW_LDTOKENCONST (cfg, ins, image, n);
9331                                         } else {
9332                                                 EMIT_NEW_PCONST (cfg, ins, handle);
9333                                         }
9334                                         EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9335                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, addr->dreg, 0, ins->dreg);
9336                                         EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9337                                 }
9338                         }
9339
9340                         *sp++ = ins;
9341                         ip += 5;
9342                         break;
9343                 }
9344                 case CEE_THROW:
9345                         CHECK_STACK (1);
9346                         MONO_INST_NEW (cfg, ins, OP_THROW);
9347                         --sp;
9348                         ins->sreg1 = sp [0]->dreg;
9349                         ip++;
9350                         bblock->out_of_line = TRUE;
9351                         MONO_ADD_INS (bblock, ins);
9352                         MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
9353                         MONO_ADD_INS (bblock, ins);
9354                         sp = stack_start;
9355                         
9356                         link_bblock (cfg, bblock, end_bblock);
9357                         start_new_bblock = 1;
9358                         break;
9359                 case CEE_ENDFINALLY:
9360                         MONO_INST_NEW (cfg, ins, OP_ENDFINALLY);
9361                         MONO_ADD_INS (bblock, ins);
9362                         ip++;
9363                         start_new_bblock = 1;
9364
9365                         /*
9366                          * Control will leave the method so empty the stack, otherwise
9367                          * the next basic block will start with a nonempty stack.
9368                          */
9369                         while (sp != stack_start) {
9370                                 sp--;
9371                         }
9372                         break;
9373                 case CEE_LEAVE:
9374                 case CEE_LEAVE_S: {
9375                         GList *handlers;
9376
9377                         if (*ip == CEE_LEAVE) {
9378                                 CHECK_OPSIZE (5);
9379                                 target = ip + 5 + (gint32)read32(ip + 1);
9380                         } else {
9381                                 CHECK_OPSIZE (2);
9382                                 target = ip + 2 + (signed char)(ip [1]);
9383                         }
9384
9385                         /* empty the stack */
9386                         while (sp != stack_start) {
9387                                 sp--;
9388                         }
9389
9390                         /* 
9391                          * If this leave statement is in a catch block, check for a
9392                          * pending exception, and rethrow it if necessary.
9393                          * We avoid doing this in runtime invoke wrappers, since those are called
9394                          * by native code which excepts the wrapper to catch all exceptions.
9395                          */
9396                         for (i = 0; i < header->num_clauses; ++i) {
9397                                 MonoExceptionClause *clause = &header->clauses [i];
9398
9399                                 /* 
9400                                  * Use <= in the final comparison to handle clauses with multiple
9401                                  * leave statements, like in bug #78024.
9402                                  * The ordering of the exception clauses guarantees that we find the
9403                                  * innermost clause.
9404                                  */
9405                                 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) {
9406                                         MonoInst *exc_ins;
9407                                         MonoBasicBlock *dont_throw;
9408
9409                                         /*
9410                                           MonoInst *load;
9411
9412                                           NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, clause->handler_offset)->inst_c0);
9413                                         */
9414
9415                                         exc_ins = mono_emit_jit_icall (cfg, mono_thread_get_undeniable_exception, NULL);
9416
9417                                         NEW_BBLOCK (cfg, dont_throw);
9418
9419                                         /*
9420                                          * Currently, we always rethrow the abort exception, despite the 
9421                                          * fact that this is not correct. See thread6.cs for an example. 
9422                                          * But propagating the abort exception is more important than 
9423                                          * getting the sematics right.
9424                                          */
9425                                         MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, exc_ins->dreg, 0);
9426                                         MONO_EMIT_NEW_BRANCH_BLOCK (cfg, OP_PBEQ, dont_throw);
9427                                         MONO_EMIT_NEW_UNALU (cfg, OP_THROW, -1, exc_ins->dreg);
9428
9429                                         MONO_START_BB (cfg, dont_throw);
9430                                         bblock = cfg->cbb;
9431                                 }
9432                         }
9433
9434                         if ((handlers = mono_find_final_block (cfg, ip, target, MONO_EXCEPTION_CLAUSE_FINALLY))) {
9435                                 GList *tmp;
9436                                 MonoExceptionClause *clause;
9437
9438                                 for (tmp = handlers; tmp; tmp = tmp->next) {
9439                                         clause = tmp->data;
9440                                         tblock = cfg->cil_offset_to_bb [clause->handler_offset];
9441                                         g_assert (tblock);
9442                                         link_bblock (cfg, bblock, tblock);
9443                                         MONO_INST_NEW (cfg, ins, OP_CALL_HANDLER);
9444                                         ins->inst_target_bb = tblock;
9445                                         ins->inst_eh_block = clause;
9446                                         MONO_ADD_INS (bblock, ins);
9447                                         bblock->has_call_handler = 1;
9448                                         if (COMPILE_LLVM (cfg)) {
9449                                                 MonoBasicBlock *target_bb;
9450
9451                                                 /* 
9452                                                  * Link the finally bblock with the target, since it will
9453                                                  * conceptually branch there.
9454                                                  * FIXME: Have to link the bblock containing the endfinally.
9455                                                  */
9456                                                 GET_BBLOCK (cfg, target_bb, target);
9457                                                 link_bblock (cfg, tblock, target_bb);
9458                                         }
9459                                 }
9460                                 g_list_free (handlers);
9461                         } 
9462
9463                         MONO_INST_NEW (cfg, ins, OP_BR);
9464                         MONO_ADD_INS (bblock, ins);
9465                         GET_BBLOCK (cfg, tblock, target);
9466                         link_bblock (cfg, bblock, tblock);
9467                         ins->inst_target_bb = tblock;
9468                         start_new_bblock = 1;
9469
9470                         if (*ip == CEE_LEAVE)
9471                                 ip += 5;
9472                         else
9473                                 ip += 2;
9474
9475                         break;
9476                 }
9477
9478                         /*
9479                          * Mono specific opcodes
9480                          */
9481                 case MONO_CUSTOM_PREFIX: {
9482
9483                         g_assert (method->wrapper_type != MONO_WRAPPER_NONE);
9484
9485                         CHECK_OPSIZE (2);
9486                         switch (ip [1]) {
9487                         case CEE_MONO_ICALL: {
9488                                 gpointer func;
9489                                 MonoJitICallInfo *info;
9490
9491                                 token = read32 (ip + 2);
9492                                 func = mono_method_get_wrapper_data (method, token);
9493                                 info = mono_find_jit_icall_by_addr (func);
9494                                 g_assert (info);
9495
9496                                 CHECK_STACK (info->sig->param_count);
9497                                 sp -= info->sig->param_count;
9498
9499                                 ins = mono_emit_jit_icall (cfg, info->func, sp);
9500                                 if (!MONO_TYPE_IS_VOID (info->sig->ret))
9501                                         *sp++ = ins;
9502
9503                                 ip += 6;
9504                                 inline_costs += 10 * num_calls++;
9505
9506                                 break;
9507                         }
9508                         case CEE_MONO_LDPTR: {
9509                                 gpointer ptr;
9510
9511                                 CHECK_STACK_OVF (1);
9512                                 CHECK_OPSIZE (6);
9513                                 token = read32 (ip + 2);
9514
9515                                 ptr = mono_method_get_wrapper_data (method, token);
9516                                 if (cfg->compile_aot && (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) && (strstr (method->name, "__icall_wrapper_") == method->name)) {
9517                                         MonoJitICallInfo *callinfo;
9518                                         const char *icall_name;
9519
9520                                         icall_name = method->name + strlen ("__icall_wrapper_");
9521                                         g_assert (icall_name);
9522                                         callinfo = mono_find_jit_icall_by_name (icall_name);
9523                                         g_assert (callinfo);
9524                                                 
9525                                         if (ptr == callinfo->func) {
9526                                                 /* Will be transformed into an AOTCONST later */
9527                                                 EMIT_NEW_PCONST (cfg, ins, ptr);
9528                                                 *sp++ = ins;
9529                                                 ip += 6;
9530                                                 break;
9531                                         }
9532                                 }
9533                                 /* FIXME: Generalize this */
9534                                 if (cfg->compile_aot && ptr == mono_thread_interruption_request_flag ()) {
9535                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL);
9536                                         *sp++ = ins;
9537                                         ip += 6;
9538                                         break;
9539                                 }
9540                                 EMIT_NEW_PCONST (cfg, ins, ptr);
9541                                 *sp++ = ins;
9542                                 ip += 6;
9543                                 inline_costs += 10 * num_calls++;
9544                                 /* Can't embed random pointers into AOT code */
9545                                 cfg->disable_aot = 1;
9546                                 break;
9547                         }
9548                         case CEE_MONO_ICALL_ADDR: {
9549                                 MonoMethod *cmethod;
9550                                 gpointer ptr;
9551
9552                                 CHECK_STACK_OVF (1);
9553                                 CHECK_OPSIZE (6);
9554                                 token = read32 (ip + 2);
9555
9556                                 cmethod = mono_method_get_wrapper_data (method, token);
9557
9558                                 if (cfg->compile_aot) {
9559                                         EMIT_NEW_AOTCONST (cfg, ins, MONO_PATCH_INFO_ICALL_ADDR, cmethod);
9560                                 } else {
9561                                         ptr = mono_lookup_internal_call (cmethod);
9562                                         g_assert (ptr);
9563                                         EMIT_NEW_PCONST (cfg, ins, ptr);
9564                                 }
9565                                 *sp++ = ins;
9566                                 ip += 6;
9567                                 break;
9568                         }
9569                         case CEE_MONO_VTADDR: {
9570                                 MonoInst *src_var, *src;
9571
9572                                 CHECK_STACK (1);
9573                                 --sp;
9574
9575                                 // FIXME:
9576                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
9577                                 EMIT_NEW_VARLOADA ((cfg), (src), src_var, src_var->inst_vtype);
9578                                 *sp++ = src;
9579                                 ip += 2;
9580                                 break;
9581                         }
9582                         case CEE_MONO_NEWOBJ: {
9583                                 MonoInst *iargs [2];
9584
9585                                 CHECK_STACK_OVF (1);
9586                                 CHECK_OPSIZE (6);
9587                                 token = read32 (ip + 2);
9588                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9589                                 mono_class_init (klass);
9590                                 NEW_DOMAINCONST (cfg, iargs [0]);
9591                                 MONO_ADD_INS (cfg->cbb, iargs [0]);
9592                                 NEW_CLASSCONST (cfg, iargs [1], klass);
9593                                 MONO_ADD_INS (cfg->cbb, iargs [1]);
9594                                 *sp++ = mono_emit_jit_icall (cfg, mono_object_new, iargs);
9595                                 ip += 6;
9596                                 inline_costs += 10 * num_calls++;
9597                                 break;
9598                         }
9599                         case CEE_MONO_OBJADDR:
9600                                 CHECK_STACK (1);
9601                                 --sp;
9602                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
9603                                 ins->dreg = alloc_preg (cfg);
9604                                 ins->sreg1 = sp [0]->dreg;
9605                                 ins->type = STACK_MP;
9606                                 MONO_ADD_INS (cfg->cbb, ins);
9607                                 *sp++ = ins;
9608                                 ip += 2;
9609                                 break;
9610                         case CEE_MONO_LDNATIVEOBJ:
9611                                 /*
9612                                  * Similar to LDOBJ, but instead load the unmanaged 
9613                                  * representation of the vtype to the stack.
9614                                  */
9615                                 CHECK_STACK (1);
9616                                 CHECK_OPSIZE (6);
9617                                 --sp;
9618                                 token = read32 (ip + 2);
9619                                 klass = mono_method_get_wrapper_data (method, token);
9620                                 g_assert (klass->valuetype);
9621                                 mono_class_init (klass);
9622
9623                                 {
9624                                         MonoInst *src, *dest, *temp;
9625
9626                                         src = sp [0];
9627                                         temp = mono_compile_create_var (cfg, &klass->byval_arg, OP_LOCAL);
9628                                         temp->backend.is_pinvoke = 1;
9629                                         EMIT_NEW_TEMPLOADA (cfg, dest, temp->inst_c0);
9630                                         mini_emit_stobj (cfg, dest, src, klass, TRUE);
9631
9632                                         EMIT_NEW_TEMPLOAD (cfg, dest, temp->inst_c0);
9633                                         dest->type = STACK_VTYPE;
9634                                         dest->klass = klass;
9635
9636                                         *sp ++ = dest;
9637                                         ip += 6;
9638                                 }
9639                                 break;
9640                         case CEE_MONO_RETOBJ: {
9641                                 /*
9642                                  * Same as RET, but return the native representation of a vtype
9643                                  * to the caller.
9644                                  */
9645                                 g_assert (cfg->ret);
9646                                 g_assert (mono_method_signature (method)->pinvoke); 
9647                                 CHECK_STACK (1);
9648                                 --sp;
9649                                 
9650                                 CHECK_OPSIZE (6);
9651                                 token = read32 (ip + 2);    
9652                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9653
9654                                 if (!cfg->vret_addr) {
9655                                         g_assert (cfg->ret_var_is_local);
9656
9657                                         EMIT_NEW_VARLOADA (cfg, ins, cfg->ret, cfg->ret->inst_vtype);
9658                                 } else {
9659                                         EMIT_NEW_RETLOADA (cfg, ins);
9660                                 }
9661                                 mini_emit_stobj (cfg, ins, sp [0], klass, TRUE);
9662                                 
9663                                 if (sp != stack_start)
9664                                         UNVERIFIED;
9665                                 
9666                                 MONO_INST_NEW (cfg, ins, OP_BR);
9667                                 ins->inst_target_bb = end_bblock;
9668                                 MONO_ADD_INS (bblock, ins);
9669                                 link_bblock (cfg, bblock, end_bblock);
9670                                 start_new_bblock = 1;
9671                                 ip += 6;
9672                                 break;
9673                         }
9674                         case CEE_MONO_CISINST:
9675                         case CEE_MONO_CCASTCLASS: {
9676                                 int token;
9677                                 CHECK_STACK (1);
9678                                 --sp;
9679                                 CHECK_OPSIZE (6);
9680                                 token = read32 (ip + 2);
9681                                 klass = (MonoClass *)mono_method_get_wrapper_data (method, token);
9682                                 if (ip [1] == CEE_MONO_CISINST)
9683                                         ins = handle_cisinst (cfg, klass, sp [0]);
9684                                 else
9685                                         ins = handle_ccastclass (cfg, klass, sp [0]);
9686                                 bblock = cfg->cbb;
9687                                 *sp++ = ins;
9688                                 ip += 6;
9689                                 break;
9690                         }
9691                         case CEE_MONO_SAVE_LMF:
9692                         case CEE_MONO_RESTORE_LMF:
9693 #ifdef MONO_ARCH_HAVE_LMF_OPS
9694                                 MONO_INST_NEW (cfg, ins, (ip [1] == CEE_MONO_SAVE_LMF) ? OP_SAVE_LMF : OP_RESTORE_LMF);
9695                                 MONO_ADD_INS (bblock, ins);
9696                                 cfg->need_lmf_area = TRUE;
9697 #endif
9698                                 ip += 2;
9699                                 break;
9700                         case CEE_MONO_CLASSCONST:
9701                                 CHECK_STACK_OVF (1);
9702                                 CHECK_OPSIZE (6);
9703                                 token = read32 (ip + 2);
9704                                 EMIT_NEW_CLASSCONST (cfg, ins, mono_method_get_wrapper_data (method, token));
9705                                 *sp++ = ins;
9706                                 ip += 6;
9707                                 inline_costs += 10 * num_calls++;
9708                                 break;
9709                         case CEE_MONO_NOT_TAKEN:
9710                                 bblock->out_of_line = TRUE;
9711                                 ip += 2;
9712                                 break;
9713                         case CEE_MONO_TLS:
9714                                 CHECK_STACK_OVF (1);
9715                                 CHECK_OPSIZE (6);
9716                                 MONO_INST_NEW (cfg, ins, OP_TLS_GET);
9717                                 ins->dreg = alloc_preg (cfg);
9718                                 ins->inst_offset = (gint32)read32 (ip + 2);
9719                                 ins->type = STACK_PTR;
9720                                 MONO_ADD_INS (bblock, ins);
9721                                 *sp++ = ins;
9722                                 ip += 6;
9723                                 break;
9724                         case CEE_MONO_DYN_CALL: {
9725                                 MonoCallInst *call;
9726
9727                                 /* It would be easier to call a trampoline, but that would put an
9728                                  * extra frame on the stack, confusing exception handling. So
9729                                  * implement it inline using an opcode for now.
9730                                  */
9731
9732                                 if (!cfg->dyn_call_var) {
9733                                         cfg->dyn_call_var = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
9734                                         /* prevent it from being register allocated */
9735                                         cfg->dyn_call_var->flags |= MONO_INST_INDIRECT;
9736                                 }
9737
9738                                 /* Has to use a call inst since it local regalloc expects it */
9739                                 MONO_INST_NEW_CALL (cfg, call, OP_DYN_CALL);
9740                                 ins = (MonoInst*)call;
9741                                 sp -= 2;
9742                                 ins->sreg1 = sp [0]->dreg;
9743                                 ins->sreg2 = sp [1]->dreg;
9744                                 MONO_ADD_INS (bblock, ins);
9745
9746 #ifdef MONO_ARCH_DYN_CALL_PARAM_AREA
9747                                 cfg->param_area = MAX (cfg->param_area, MONO_ARCH_DYN_CALL_PARAM_AREA);
9748 #endif
9749
9750                                 ip += 2;
9751                                 inline_costs += 10 * num_calls++;
9752
9753                                 break;
9754                         }
9755                         default:
9756                                 g_error ("opcode 0x%02x 0x%02x not handled", MONO_CUSTOM_PREFIX, ip [1]);
9757                                 break;
9758                         }
9759                         break;
9760                 }
9761
9762                 case CEE_PREFIX1: {
9763                         CHECK_OPSIZE (2);
9764                         switch (ip [1]) {
9765                         case CEE_ARGLIST: {
9766                                 /* somewhat similar to LDTOKEN */
9767                                 MonoInst *addr, *vtvar;
9768                                 CHECK_STACK_OVF (1);
9769                                 vtvar = mono_compile_create_var (cfg, &mono_defaults.argumenthandle_class->byval_arg, OP_LOCAL); 
9770
9771                                 EMIT_NEW_TEMPLOADA (cfg, addr, vtvar->inst_c0);
9772                                 EMIT_NEW_UNALU (cfg, ins, OP_ARGLIST, -1, addr->dreg);
9773
9774                                 EMIT_NEW_TEMPLOAD (cfg, ins, vtvar->inst_c0);
9775                                 ins->type = STACK_VTYPE;
9776                                 ins->klass = mono_defaults.argumenthandle_class;
9777                                 *sp++ = ins;
9778                                 ip += 2;
9779                                 break;
9780                         }
9781                         case CEE_CEQ:
9782                         case CEE_CGT:
9783                         case CEE_CGT_UN:
9784                         case CEE_CLT:
9785                         case CEE_CLT_UN: {
9786                                 MonoInst *cmp;
9787                                 CHECK_STACK (2);
9788                                 /*
9789                                  * The following transforms:
9790                                  *    CEE_CEQ    into OP_CEQ
9791                                  *    CEE_CGT    into OP_CGT
9792                                  *    CEE_CGT_UN into OP_CGT_UN
9793                                  *    CEE_CLT    into OP_CLT
9794                                  *    CEE_CLT_UN into OP_CLT_UN
9795                                  */
9796                                 MONO_INST_NEW (cfg, cmp, (OP_CEQ - CEE_CEQ) + ip [1]);
9797                                 
9798                                 MONO_INST_NEW (cfg, ins, cmp->opcode);
9799                                 sp -= 2;
9800                                 cmp->sreg1 = sp [0]->dreg;
9801                                 cmp->sreg2 = sp [1]->dreg;
9802                                 type_from_op (cmp, sp [0], sp [1]);
9803                                 CHECK_TYPE (cmp);
9804                                 if ((sp [0]->type == STACK_I8) || ((SIZEOF_REGISTER == 8) && ((sp [0]->type == STACK_PTR) || (sp [0]->type == STACK_OBJ) || (sp [0]->type == STACK_MP))))
9805                                         cmp->opcode = OP_LCOMPARE;
9806                                 else if (sp [0]->type == STACK_R8)
9807                                         cmp->opcode = OP_FCOMPARE;
9808                                 else
9809                                         cmp->opcode = OP_ICOMPARE;
9810                                 MONO_ADD_INS (bblock, cmp);
9811                                 ins->type = STACK_I4;
9812                                 ins->dreg = alloc_dreg (cfg, ins->type);
9813                                 type_from_op (ins, sp [0], sp [1]);
9814
9815                                 if (cmp->opcode == OP_FCOMPARE) {
9816                                         /*
9817                                          * The backends expect the fceq opcodes to do the
9818                                          * comparison too.
9819                                          */
9820                                         cmp->opcode = OP_NOP;
9821                                         ins->sreg1 = cmp->sreg1;
9822                                         ins->sreg2 = cmp->sreg2;
9823                                 }
9824                                 MONO_ADD_INS (bblock, ins);
9825                                 *sp++ = ins;
9826                                 ip += 2;
9827                                 break;
9828                         }
9829                         case CEE_LDFTN: {
9830                                 MonoInst *argconst;
9831                                 MonoMethod *cil_method;
9832                                 gboolean needs_static_rgctx_invoke;
9833
9834                                 CHECK_STACK_OVF (1);
9835                                 CHECK_OPSIZE (6);
9836                                 n = read32 (ip + 2);
9837                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9838                                 if (!cmethod || mono_loader_get_last_error ())
9839                                         LOAD_ERROR;
9840                                 mono_class_init (cmethod->klass);
9841
9842                                 mono_save_token_info (cfg, image, n, cmethod);
9843
9844                                 if (cfg->generic_sharing_context)
9845                                         context_used = mono_method_check_context_used (cmethod);
9846
9847                                 needs_static_rgctx_invoke = mono_method_needs_static_rgctx_invoke (cmethod, TRUE);
9848  
9849                                 cil_method = cmethod;
9850                                 if (!dont_verify && !cfg->skip_visibility && !mono_method_can_access_method (method, cmethod))
9851                                         METHOD_ACCESS_FAILURE;
9852
9853                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9854                                         if (check_linkdemand (cfg, method, cmethod))
9855                                                 INLINE_FAILURE;
9856                                         CHECK_CFG_EXCEPTION;
9857                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9858                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9859                                 }
9860
9861                                 /* 
9862                                  * Optimize the common case of ldftn+delegate creation
9863                                  */
9864                                 if ((sp > stack_start) && (ip + 6 + 5 < end) && ip_in_bb (cfg, bblock, ip + 6) && (ip [6] == CEE_NEWOBJ)) {
9865                                         MonoMethod *ctor_method = mini_get_method (cfg, method, read32 (ip + 7), NULL, generic_context);
9866                                         if (ctor_method && (ctor_method->klass->parent == mono_defaults.multicastdelegate_class)) {
9867                                                 MonoInst *target_ins;
9868                                                 MonoMethod *invoke;
9869                                                 int invoke_context_used = 0;
9870
9871                                                 invoke = mono_get_delegate_invoke (ctor_method->klass);
9872                                                 if (!invoke || !mono_method_signature (invoke))
9873                                                         LOAD_ERROR;
9874
9875                                                 if (cfg->generic_sharing_context)
9876                                                         invoke_context_used = mono_method_check_context_used (invoke);
9877
9878                                                 target_ins = sp [-1];
9879
9880                                                 if (!(cmethod->flags & METHOD_ATTRIBUTE_STATIC)) {
9881                                                         /*LAME IMPL: We must not add a null check for virtual invoke delegates.*/
9882                                                         if (mono_method_signature (invoke)->param_count == mono_method_signature (cmethod)->param_count) {
9883                                                                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_COMPARE_IMM, -1, target_ins->dreg, 0);
9884                                                                 MONO_EMIT_NEW_COND_EXC (cfg, EQ, "ArgumentException");
9885                                                         }
9886                                                 }
9887
9888 #if defined(MONO_ARCH_HAVE_CREATE_DELEGATE_TRAMPOLINE)
9889                                                 /* FIXME: SGEN support */
9890                                                 if (invoke_context_used == 0) {
9891                                                         ip += 6;
9892                                                         if (cfg->verbose_level > 3)
9893                                                                 g_print ("converting (in B%d: stack: %d) %s", bblock->block_num, (int)(sp - stack_start), mono_disasm_code_one (NULL, method, ip, NULL));
9894                                                         sp --;
9895                                                         *sp = handle_delegate_ctor (cfg, ctor_method->klass, target_ins, cmethod, context_used);
9896                                                         CHECK_CFG_EXCEPTION;
9897                                                         ip += 5;                        
9898                                                         sp ++;
9899                                                         break;
9900                                                 }
9901 #endif
9902                                         }
9903                                 }
9904
9905                                 argconst = emit_get_rgctx_method (cfg, context_used, cmethod, MONO_RGCTX_INFO_METHOD);
9906                                 ins = mono_emit_jit_icall (cfg, mono_ldftn, &argconst);
9907                                 *sp++ = ins;
9908                                 
9909                                 ip += 6;
9910                                 inline_costs += 10 * num_calls++;
9911                                 break;
9912                         }
9913                         case CEE_LDVIRTFTN: {
9914                                 MonoInst *args [2];
9915
9916                                 CHECK_STACK (1);
9917                                 CHECK_OPSIZE (6);
9918                                 n = read32 (ip + 2);
9919                                 cmethod = mini_get_method (cfg, method, n, NULL, generic_context);
9920                                 if (!cmethod || mono_loader_get_last_error ())
9921                                         LOAD_ERROR;
9922                                 mono_class_init (cmethod->klass);
9923  
9924                                 if (cfg->generic_sharing_context)
9925                                         context_used = mono_method_check_context_used (cmethod);
9926
9927                                 if (mono_security_get_mode () == MONO_SECURITY_MODE_CAS) {
9928                                         if (check_linkdemand (cfg, method, cmethod))
9929                                                 INLINE_FAILURE;
9930                                         CHECK_CFG_EXCEPTION;
9931                                 } else if (mono_security_get_mode () == MONO_SECURITY_MODE_CORE_CLR) {
9932                                         ensure_method_is_allowed_to_call_method (cfg, method, cmethod, bblock, ip);
9933                                 }
9934
9935                                 --sp;
9936                                 args [0] = *sp;
9937
9938                                 args [1] = emit_get_rgctx_method (cfg, context_used,
9939                                                                                                   cmethod, MONO_RGCTX_INFO_METHOD);
9940
9941                                 if (context_used)
9942                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn_gshared, args);
9943                                 else
9944                                         *sp++ = mono_emit_jit_icall (cfg, mono_ldvirtfn, args);
9945
9946                                 ip += 6;
9947                                 inline_costs += 10 * num_calls++;
9948                                 break;
9949                         }
9950                         case CEE_LDARG:
9951                                 CHECK_STACK_OVF (1);
9952                                 CHECK_OPSIZE (4);
9953                                 n = read16 (ip + 2);
9954                                 CHECK_ARG (n);
9955                                 EMIT_NEW_ARGLOAD (cfg, ins, n);
9956                                 *sp++ = ins;
9957                                 ip += 4;
9958                                 break;
9959                         case CEE_LDARGA:
9960                                 CHECK_STACK_OVF (1);
9961                                 CHECK_OPSIZE (4);
9962                                 n = read16 (ip + 2);
9963                                 CHECK_ARG (n);
9964                                 NEW_ARGLOADA (cfg, ins, n);
9965                                 MONO_ADD_INS (cfg->cbb, ins);
9966                                 *sp++ = ins;
9967                                 ip += 4;
9968                                 break;
9969                         case CEE_STARG:
9970                                 CHECK_STACK (1);
9971                                 --sp;
9972                                 CHECK_OPSIZE (4);
9973                                 n = read16 (ip + 2);
9974                                 CHECK_ARG (n);
9975                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, param_types [n], *sp))
9976                                         UNVERIFIED;
9977                                 EMIT_NEW_ARGSTORE (cfg, ins, n, *sp);
9978                                 ip += 4;
9979                                 break;
9980                         case CEE_LDLOC:
9981                                 CHECK_STACK_OVF (1);
9982                                 CHECK_OPSIZE (4);
9983                                 n = read16 (ip + 2);
9984                                 CHECK_LOCAL (n);
9985                                 EMIT_NEW_LOCLOAD (cfg, ins, n);
9986                                 *sp++ = ins;
9987                                 ip += 4;
9988                                 break;
9989                         case CEE_LDLOCA: {
9990                                 unsigned char *tmp_ip;
9991                                 CHECK_STACK_OVF (1);
9992                                 CHECK_OPSIZE (4);
9993                                 n = read16 (ip + 2);
9994                                 CHECK_LOCAL (n);
9995
9996                                 if ((tmp_ip = emit_optimized_ldloca_ir (cfg, ip, end, 2))) {
9997                                         ip = tmp_ip;
9998                                         inline_costs += 1;
9999                                         break;
10000                                 }                       
10001                                 
10002                                 EMIT_NEW_LOCLOADA (cfg, ins, n);
10003                                 *sp++ = ins;
10004                                 ip += 4;
10005                                 break;
10006                         }
10007                         case CEE_STLOC:
10008                                 CHECK_STACK (1);
10009                                 --sp;
10010                                 CHECK_OPSIZE (4);
10011                                 n = read16 (ip + 2);
10012                                 CHECK_LOCAL (n);
10013                                 if (!dont_verify_stloc && target_type_is_incompatible (cfg, header->locals [n], *sp))
10014                                         UNVERIFIED;
10015                                 emit_stloc_ir (cfg, sp, header, n);
10016                                 ip += 4;
10017                                 inline_costs += 1;
10018                                 break;
10019                         case CEE_LOCALLOC:
10020                                 CHECK_STACK (1);
10021                                 --sp;
10022                                 if (sp != stack_start) 
10023                                         UNVERIFIED;
10024                                 if (cfg->method != method) 
10025                                         /* 
10026                                          * Inlining this into a loop in a parent could lead to 
10027                                          * stack overflows which is different behavior than the
10028                                          * non-inlined case, thus disable inlining in this case.
10029                                          */
10030                                         goto inline_failure;
10031
10032                                 MONO_INST_NEW (cfg, ins, OP_LOCALLOC);
10033                                 ins->dreg = alloc_preg (cfg);
10034                                 ins->sreg1 = sp [0]->dreg;
10035                                 ins->type = STACK_PTR;
10036                                 MONO_ADD_INS (cfg->cbb, ins);
10037
10038                                 cfg->flags |= MONO_CFG_HAS_ALLOCA;
10039                                 if (init_locals)
10040                                         ins->flags |= MONO_INST_INIT;
10041
10042                                 *sp++ = ins;
10043                                 ip += 2;
10044                                 break;
10045                         case CEE_ENDFILTER: {
10046                                 MonoExceptionClause *clause, *nearest;
10047                                 int cc, nearest_num;
10048
10049                                 CHECK_STACK (1);
10050                                 --sp;
10051                                 if ((sp != stack_start) || (sp [0]->type != STACK_I4)) 
10052                                         UNVERIFIED;
10053                                 MONO_INST_NEW (cfg, ins, OP_ENDFILTER);
10054                                 ins->sreg1 = (*sp)->dreg;
10055                                 MONO_ADD_INS (bblock, ins);
10056                                 start_new_bblock = 1;
10057                                 ip += 2;
10058
10059                                 nearest = NULL;
10060                                 nearest_num = 0;
10061                                 for (cc = 0; cc < header->num_clauses; ++cc) {
10062                                         clause = &header->clauses [cc];
10063                                         if ((clause->flags & MONO_EXCEPTION_CLAUSE_FILTER) &&
10064                                                 ((ip - header->code) > clause->data.filter_offset && (ip - header->code) <= clause->handler_offset) &&
10065                                             (!nearest || (clause->data.filter_offset < nearest->data.filter_offset))) {
10066                                                 nearest = clause;
10067                                                 nearest_num = cc;
10068                                         }
10069                                 }
10070                                 g_assert (nearest);
10071                                 if ((ip - header->code) != nearest->handler_offset)
10072                                         UNVERIFIED;
10073
10074                                 break;
10075                         }
10076                         case CEE_UNALIGNED_:
10077                                 ins_flag |= MONO_INST_UNALIGNED;
10078                                 /* FIXME: record alignment? we can assume 1 for now */
10079                                 CHECK_OPSIZE (3);
10080                                 ip += 3;
10081                                 break;
10082                         case CEE_VOLATILE_:
10083                                 ins_flag |= MONO_INST_VOLATILE;
10084                                 ip += 2;
10085                                 break;
10086                         case CEE_TAIL_:
10087                                 ins_flag   |= MONO_INST_TAILCALL;
10088                                 cfg->flags |= MONO_CFG_HAS_TAIL;
10089                                 /* Can't inline tail calls at this time */
10090                                 inline_costs += 100000;
10091                                 ip += 2;
10092                                 break;
10093                         case CEE_INITOBJ:
10094                                 CHECK_STACK (1);
10095                                 --sp;
10096                                 CHECK_OPSIZE (6);
10097                                 token = read32 (ip + 2);
10098                                 klass = mini_get_class (method, token, generic_context);
10099                                 CHECK_TYPELOAD (klass);
10100                                 if (generic_class_is_reference_type (cfg, klass))
10101                                         MONO_EMIT_NEW_STORE_MEMBASE_IMM (cfg, OP_STORE_MEMBASE_IMM, sp [0]->dreg, 0, 0);
10102                                 else
10103                                         mini_emit_initobj (cfg, *sp, NULL, klass);
10104                                 ip += 6;
10105                                 inline_costs += 1;
10106                                 break;
10107                         case CEE_CONSTRAINED_:
10108                                 CHECK_OPSIZE (6);
10109                                 token = read32 (ip + 2);
10110                                 if (method->wrapper_type != MONO_WRAPPER_NONE)
10111                                         constrained_call =  (MonoClass *)mono_method_get_wrapper_data (method, token);
10112                                 else
10113                                         constrained_call = mono_class_get_full (image, token, generic_context);
10114                                 CHECK_TYPELOAD (constrained_call);
10115                                 ip += 6;
10116                                 break;
10117                         case CEE_CPBLK:
10118                         case CEE_INITBLK: {
10119                                 MonoInst *iargs [3];
10120                                 CHECK_STACK (3);
10121                                 sp -= 3;
10122
10123                                 if ((ip [1] == CEE_CPBLK) && (cfg->opt & MONO_OPT_INTRINS) && (sp [2]->opcode == OP_ICONST) && ((n = sp [2]->inst_c0) <= sizeof (gpointer) * 5)) {
10124                                         mini_emit_memcpy (cfg, sp [0]->dreg, 0, sp [1]->dreg, 0, sp [2]->inst_c0, 0);
10125                                 } 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)) {
10126                                         /* emit_memset only works when val == 0 */
10127                                         mini_emit_memset (cfg, sp [0]->dreg, 0, sp [2]->inst_c0, sp [1]->inst_c0, 0);
10128                                 } else {
10129                                         iargs [0] = sp [0];
10130                                         iargs [1] = sp [1];
10131                                         iargs [2] = sp [2];
10132                                         if (ip [1] == CEE_CPBLK) {
10133                                                 MonoMethod *memcpy_method = get_memcpy_method ();
10134                                                 mono_emit_method_call (cfg, memcpy_method, iargs, NULL);
10135                                         } else {
10136                                                 MonoMethod *memset_method = get_memset_method ();
10137                                                 mono_emit_method_call (cfg, memset_method, iargs, NULL);
10138                                         }
10139                                 }
10140                                 ip += 2;
10141                                 inline_costs += 1;
10142                                 break;
10143                         }
10144                         case CEE_NO_:
10145                                 CHECK_OPSIZE (3);
10146                                 if (ip [2] & 0x1)
10147                                         ins_flag |= MONO_INST_NOTYPECHECK;
10148                                 if (ip [2] & 0x2)
10149                                         ins_flag |= MONO_INST_NORANGECHECK;
10150                                 /* we ignore the no-nullcheck for now since we
10151                                  * really do it explicitly only when doing callvirt->call
10152                                  */
10153                                 ip += 3;
10154                                 break;
10155                         case CEE_RETHROW: {
10156                                 MonoInst *load;
10157                                 int handler_offset = -1;
10158
10159                                 for (i = 0; i < header->num_clauses; ++i) {
10160                                         MonoExceptionClause *clause = &header->clauses [i];
10161                                         if (MONO_OFFSET_IN_HANDLER (clause, ip - header->code) && !(clause->flags & MONO_EXCEPTION_CLAUSE_FINALLY)) {
10162                                                 handler_offset = clause->handler_offset;
10163                                                 break;
10164                                         }
10165                                 }
10166
10167                                 bblock->flags |= BB_EXCEPTION_UNSAFE;
10168
10169                                 g_assert (handler_offset != -1);
10170
10171                                 EMIT_NEW_TEMPLOAD (cfg, load, mono_find_exvar_for_offset (cfg, handler_offset)->inst_c0);
10172                                 MONO_INST_NEW (cfg, ins, OP_RETHROW);
10173                                 ins->sreg1 = load->dreg;
10174                                 MONO_ADD_INS (bblock, ins);
10175
10176                                 MONO_INST_NEW (cfg, ins, OP_NOT_REACHED);
10177                                 MONO_ADD_INS (bblock, ins);
10178
10179                                 sp = stack_start;
10180                                 link_bblock (cfg, bblock, end_bblock);
10181                                 start_new_bblock = 1;
10182                                 ip += 2;
10183                                 break;
10184                         }
10185                         case CEE_SIZEOF: {
10186                                 guint32 align;
10187                                 int ialign;
10188
10189                                 CHECK_STACK_OVF (1);
10190                                 CHECK_OPSIZE (6);
10191                                 token = read32 (ip + 2);
10192                                 if (mono_metadata_token_table (token) == MONO_TABLE_TYPESPEC && !method->klass->image->dynamic) {
10193                                         MonoType *type = mono_type_create_from_typespec (image, token);
10194                                         token = mono_type_size (type, &ialign);
10195                                 } else {
10196                                         MonoClass *klass = mono_class_get_full (image, token, generic_context);
10197                                         CHECK_TYPELOAD (klass);
10198                                         mono_class_init (klass);
10199                                         token = mono_class_value_size (klass, &align);
10200                                 }
10201                                 EMIT_NEW_ICONST (cfg, ins, token);
10202                                 *sp++= ins;
10203                                 ip += 6;
10204                                 break;
10205                         }
10206                         case CEE_REFANYTYPE: {
10207                                 MonoInst *src_var, *src;
10208
10209                                 CHECK_STACK (1);
10210                                 --sp;
10211
10212                                 // FIXME:
10213                                 src_var = get_vreg_to_inst (cfg, sp [0]->dreg);
10214                                 if (!src_var)
10215                                         src_var = mono_compile_create_var_for_vreg (cfg, &mono_defaults.typed_reference_class->byval_arg, OP_LOCAL, sp [0]->dreg);
10216                                 EMIT_NEW_VARLOADA (cfg, src, src_var, src_var->inst_vtype);
10217                                 EMIT_NEW_LOAD_MEMBASE_TYPE (cfg, ins, &mono_defaults.typehandle_class->byval_arg, src->dreg, G_STRUCT_OFFSET (MonoTypedRef, type));
10218                                 *sp++ = ins;
10219                                 ip += 2;
10220                                 break;
10221                         }
10222                         case CEE_READONLY_:
10223                                 readonly = TRUE;
10224                                 ip += 2;
10225                                 break;
10226
10227                         case CEE_UNUSED56:
10228                         case CEE_UNUSED57:
10229                         case CEE_UNUSED70:
10230                         case CEE_UNUSED:
10231                         case CEE_UNUSED99:
10232                                 UNVERIFIED;
10233                                 
10234                         default:
10235                                 g_warning ("opcode 0xfe 0x%02x not handled", ip [1]);
10236                                 UNVERIFIED;
10237                         }
10238                         break;
10239                 }
10240                 case CEE_UNUSED58:
10241                 case CEE_UNUSED1:
10242                         UNVERIFIED;
10243
10244                 default:
10245                         g_warning ("opcode 0x%02x not handled", *ip);
10246                         UNVERIFIED;
10247                 }
10248         }
10249         if (start_new_bblock != 1)
10250                 UNVERIFIED;
10251
10252         bblock->cil_length = ip - bblock->cil_code;
10253         bblock->next_bb = end_bblock;
10254
10255         if (cfg->method == method && cfg->domainvar) {
10256                 MonoInst *store;
10257                 MonoInst *get_domain;
10258
10259                 cfg->cbb = init_localsbb;
10260
10261                 if (! (get_domain = mono_arch_get_domain_intrinsic (cfg))) {
10262                         get_domain = mono_emit_jit_icall (cfg, mono_domain_get, NULL);
10263                 }
10264                 else {
10265                         get_domain->dreg = alloc_preg (cfg);
10266                         MONO_ADD_INS (cfg->cbb, get_domain);
10267                 }               
10268                 NEW_TEMPSTORE (cfg, store, cfg->domainvar->inst_c0, get_domain);
10269                 MONO_ADD_INS (cfg->cbb, store);
10270         }
10271
10272 #if defined(TARGET_POWERPC) || defined(TARGET_X86)
10273         if (cfg->compile_aot)
10274                 /* FIXME: The plt slots require a GOT var even if the method doesn't use it */
10275                 mono_get_got_var (cfg);
10276 #endif
10277
10278         if (cfg->method == method && cfg->got_var)
10279                 mono_emit_load_got_addr (cfg);
10280
10281         if (init_locals) {
10282                 MonoInst *store;
10283
10284                 cfg->cbb = init_localsbb;
10285                 cfg->ip = NULL;
10286                 for (i = 0; i < header->num_locals; ++i) {
10287                         MonoType *ptype = header->locals [i];
10288                         int t = ptype->type;
10289                         dreg = cfg->locals [i]->dreg;
10290
10291                         if (t == MONO_TYPE_VALUETYPE && ptype->data.klass->enumtype)
10292                                 t = mono_class_enum_basetype (ptype->data.klass)->type;
10293                         if (ptype->byref) {
10294                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
10295                         } else if (t >= MONO_TYPE_BOOLEAN && t <= MONO_TYPE_U4) {
10296                                 MONO_EMIT_NEW_ICONST (cfg, cfg->locals [i]->dreg, 0);
10297                         } else if (t == MONO_TYPE_I8 || t == MONO_TYPE_U8) {
10298                                 MONO_EMIT_NEW_I8CONST (cfg, cfg->locals [i]->dreg, 0);
10299                         } else if (t == MONO_TYPE_R4 || t == MONO_TYPE_R8) {
10300                                 MONO_INST_NEW (cfg, ins, OP_R8CONST);
10301                                 ins->type = STACK_R8;
10302                                 ins->inst_p0 = (void*)&r8_0;
10303                                 ins->dreg = alloc_dreg (cfg, STACK_R8);
10304                                 MONO_ADD_INS (init_localsbb, ins);
10305                                 EMIT_NEW_LOCSTORE (cfg, store, i, ins);
10306                         } else if ((t == MONO_TYPE_VALUETYPE) || (t == MONO_TYPE_TYPEDBYREF) ||
10307                                    ((t == MONO_TYPE_GENERICINST) && mono_type_generic_inst_is_valuetype (ptype))) {
10308                                 MONO_EMIT_NEW_VZERO (cfg, dreg, mono_class_from_mono_type (ptype));
10309                         } else {
10310                                 MONO_EMIT_NEW_PCONST (cfg, dreg, NULL);
10311                         }
10312                 }
10313         }
10314
10315         if (cfg->init_ref_vars && cfg->method == method) {
10316                 /* Emit initialization for ref vars */
10317                 // FIXME: Avoid duplication initialization for IL locals.
10318                 for (i = 0; i < cfg->num_varinfo; ++i) {
10319                         MonoInst *ins = cfg->varinfo [i];
10320
10321                         if (ins->opcode == OP_LOCAL && ins->type == STACK_OBJ)
10322                                 MONO_EMIT_NEW_PCONST (cfg, ins->dreg, NULL);
10323                 }
10324         }
10325
10326         /* Add a sequence point for method entry/exit events */
10327         if (seq_points) {
10328                 NEW_SEQ_POINT (cfg, ins, METHOD_ENTRY_IL_OFFSET, FALSE);
10329                 MONO_ADD_INS (init_localsbb, ins);
10330                 NEW_SEQ_POINT (cfg, ins, METHOD_EXIT_IL_OFFSET, FALSE);
10331                 MONO_ADD_INS (cfg->bb_exit, ins);
10332         }
10333
10334         cfg->ip = NULL;
10335
10336         if (cfg->method == method) {
10337                 MonoBasicBlock *bb;
10338                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10339                         bb->region = mono_find_block_region (cfg, bb->real_offset);
10340                         if (cfg->spvars)
10341                                 mono_create_spvar_for_region (cfg, bb->region);
10342                         if (cfg->verbose_level > 2)
10343                                 printf ("REGION BB%d IL_%04x ID_%08X\n", bb->block_num, bb->real_offset, bb->region);
10344                 }
10345         }
10346
10347         g_slist_free (class_inits);
10348         dont_inline = g_list_remove (dont_inline, method);
10349
10350         if (inline_costs < 0) {
10351                 char *mname;
10352
10353                 /* Method is too large */
10354                 mname = mono_method_full_name (method, TRUE);
10355                 mono_cfg_set_exception (cfg, MONO_EXCEPTION_INVALID_PROGRAM);
10356                 cfg->exception_message = g_strdup_printf ("Method %s is too complex.", mname);
10357                 g_free (mname);
10358                 cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
10359                 mono_basic_block_free (original_bb);
10360                 return -1;
10361         }
10362
10363         if ((cfg->verbose_level > 2) && (cfg->method == method)) 
10364                 mono_print_code (cfg, "AFTER METHOD-TO-IR");
10365
10366         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
10367         mono_basic_block_free (original_bb);
10368         return inline_costs;
10369  
10370  exception_exit:
10371         g_assert (cfg->exception_type != MONO_EXCEPTION_NONE);
10372         goto cleanup;
10373
10374  inline_failure:
10375         goto cleanup;
10376
10377  load_error:
10378         mono_cfg_set_exception (cfg, MONO_EXCEPTION_TYPE_LOAD);
10379         goto cleanup;
10380
10381  unverified:
10382         set_exception_type_from_invalid_il (cfg, method, ip);
10383         goto cleanup;
10384
10385  cleanup:
10386         g_slist_free (class_inits);
10387         mono_basic_block_free (original_bb);
10388         dont_inline = g_list_remove (dont_inline, method);
10389         cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header);
10390         return -1;
10391 }
10392
10393 static int
10394 store_membase_reg_to_store_membase_imm (int opcode)
10395 {
10396         switch (opcode) {
10397         case OP_STORE_MEMBASE_REG:
10398                 return OP_STORE_MEMBASE_IMM;
10399         case OP_STOREI1_MEMBASE_REG:
10400                 return OP_STOREI1_MEMBASE_IMM;
10401         case OP_STOREI2_MEMBASE_REG:
10402                 return OP_STOREI2_MEMBASE_IMM;
10403         case OP_STOREI4_MEMBASE_REG:
10404                 return OP_STOREI4_MEMBASE_IMM;
10405         case OP_STOREI8_MEMBASE_REG:
10406                 return OP_STOREI8_MEMBASE_IMM;
10407         default:
10408                 g_assert_not_reached ();
10409         }
10410
10411         return -1;
10412 }               
10413
10414 #endif /* DISABLE_JIT */
10415
10416 int
10417 mono_op_to_op_imm (int opcode)
10418 {
10419         switch (opcode) {
10420         case OP_IADD:
10421                 return OP_IADD_IMM;
10422         case OP_ISUB:
10423                 return OP_ISUB_IMM;
10424         case OP_IDIV:
10425                 return OP_IDIV_IMM;
10426         case OP_IDIV_UN:
10427                 return OP_IDIV_UN_IMM;
10428         case OP_IREM:
10429                 return OP_IREM_IMM;
10430         case OP_IREM_UN:
10431                 return OP_IREM_UN_IMM;
10432         case OP_IMUL:
10433                 return OP_IMUL_IMM;
10434         case OP_IAND:
10435                 return OP_IAND_IMM;
10436         case OP_IOR:
10437                 return OP_IOR_IMM;
10438         case OP_IXOR:
10439                 return OP_IXOR_IMM;
10440         case OP_ISHL:
10441                 return OP_ISHL_IMM;
10442         case OP_ISHR:
10443                 return OP_ISHR_IMM;
10444         case OP_ISHR_UN:
10445                 return OP_ISHR_UN_IMM;
10446
10447         case OP_LADD:
10448                 return OP_LADD_IMM;
10449         case OP_LSUB:
10450                 return OP_LSUB_IMM;
10451         case OP_LAND:
10452                 return OP_LAND_IMM;
10453         case OP_LOR:
10454                 return OP_LOR_IMM;
10455         case OP_LXOR:
10456                 return OP_LXOR_IMM;
10457         case OP_LSHL:
10458                 return OP_LSHL_IMM;
10459         case OP_LSHR:
10460                 return OP_LSHR_IMM;
10461         case OP_LSHR_UN:
10462                 return OP_LSHR_UN_IMM;          
10463
10464         case OP_COMPARE:
10465                 return OP_COMPARE_IMM;
10466         case OP_ICOMPARE:
10467                 return OP_ICOMPARE_IMM;
10468         case OP_LCOMPARE:
10469                 return OP_LCOMPARE_IMM;
10470
10471         case OP_STORE_MEMBASE_REG:
10472                 return OP_STORE_MEMBASE_IMM;
10473         case OP_STOREI1_MEMBASE_REG:
10474                 return OP_STOREI1_MEMBASE_IMM;
10475         case OP_STOREI2_MEMBASE_REG:
10476                 return OP_STOREI2_MEMBASE_IMM;
10477         case OP_STOREI4_MEMBASE_REG:
10478                 return OP_STOREI4_MEMBASE_IMM;
10479
10480 #if defined(TARGET_X86) || defined (TARGET_AMD64)
10481         case OP_X86_PUSH:
10482                 return OP_X86_PUSH_IMM;
10483         case OP_X86_COMPARE_MEMBASE_REG:
10484                 return OP_X86_COMPARE_MEMBASE_IMM;
10485 #endif
10486 #if defined(TARGET_AMD64)
10487         case OP_AMD64_ICOMPARE_MEMBASE_REG:
10488                 return OP_AMD64_ICOMPARE_MEMBASE_IMM;
10489 #endif
10490         case OP_VOIDCALL_REG:
10491                 return OP_VOIDCALL;
10492         case OP_CALL_REG:
10493                 return OP_CALL;
10494         case OP_LCALL_REG:
10495                 return OP_LCALL;
10496         case OP_FCALL_REG:
10497                 return OP_FCALL;
10498         case OP_LOCALLOC:
10499                 return OP_LOCALLOC_IMM;
10500         }
10501
10502         return -1;
10503 }
10504
10505 static int
10506 ldind_to_load_membase (int opcode)
10507 {
10508         switch (opcode) {
10509         case CEE_LDIND_I1:
10510                 return OP_LOADI1_MEMBASE;
10511         case CEE_LDIND_U1:
10512                 return OP_LOADU1_MEMBASE;
10513         case CEE_LDIND_I2:
10514                 return OP_LOADI2_MEMBASE;
10515         case CEE_LDIND_U2:
10516                 return OP_LOADU2_MEMBASE;
10517         case CEE_LDIND_I4:
10518                 return OP_LOADI4_MEMBASE;
10519         case CEE_LDIND_U4:
10520                 return OP_LOADU4_MEMBASE;
10521         case CEE_LDIND_I:
10522                 return OP_LOAD_MEMBASE;
10523         case CEE_LDIND_REF:
10524                 return OP_LOAD_MEMBASE;
10525         case CEE_LDIND_I8:
10526                 return OP_LOADI8_MEMBASE;
10527         case CEE_LDIND_R4:
10528                 return OP_LOADR4_MEMBASE;
10529         case CEE_LDIND_R8:
10530                 return OP_LOADR8_MEMBASE;
10531         default:
10532                 g_assert_not_reached ();
10533         }
10534
10535         return -1;
10536 }
10537
10538 static int
10539 stind_to_store_membase (int opcode)
10540 {
10541         switch (opcode) {
10542         case CEE_STIND_I1:
10543                 return OP_STOREI1_MEMBASE_REG;
10544         case CEE_STIND_I2:
10545                 return OP_STOREI2_MEMBASE_REG;
10546         case CEE_STIND_I4:
10547                 return OP_STOREI4_MEMBASE_REG;
10548         case CEE_STIND_I:
10549         case CEE_STIND_REF:
10550                 return OP_STORE_MEMBASE_REG;
10551         case CEE_STIND_I8:
10552                 return OP_STOREI8_MEMBASE_REG;
10553         case CEE_STIND_R4:
10554                 return OP_STORER4_MEMBASE_REG;
10555         case CEE_STIND_R8:
10556                 return OP_STORER8_MEMBASE_REG;
10557         default:
10558                 g_assert_not_reached ();
10559         }
10560
10561         return -1;
10562 }
10563
10564 int
10565 mono_load_membase_to_load_mem (int opcode)
10566 {
10567         // FIXME: Add a MONO_ARCH_HAVE_LOAD_MEM macro
10568 #if defined(TARGET_X86) || defined(TARGET_AMD64)
10569         switch (opcode) {
10570         case OP_LOAD_MEMBASE:
10571                 return OP_LOAD_MEM;
10572         case OP_LOADU1_MEMBASE:
10573                 return OP_LOADU1_MEM;
10574         case OP_LOADU2_MEMBASE:
10575                 return OP_LOADU2_MEM;
10576         case OP_LOADI4_MEMBASE:
10577                 return OP_LOADI4_MEM;
10578         case OP_LOADU4_MEMBASE:
10579                 return OP_LOADU4_MEM;
10580 #if SIZEOF_REGISTER == 8
10581         case OP_LOADI8_MEMBASE:
10582                 return OP_LOADI8_MEM;
10583 #endif
10584         }
10585 #endif
10586
10587         return -1;
10588 }
10589
10590 static inline int
10591 op_to_op_dest_membase (int store_opcode, int opcode)
10592 {
10593 #if defined(TARGET_X86)
10594         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG)))
10595                 return -1;
10596
10597         switch (opcode) {
10598         case OP_IADD:
10599                 return OP_X86_ADD_MEMBASE_REG;
10600         case OP_ISUB:
10601                 return OP_X86_SUB_MEMBASE_REG;
10602         case OP_IAND:
10603                 return OP_X86_AND_MEMBASE_REG;
10604         case OP_IOR:
10605                 return OP_X86_OR_MEMBASE_REG;
10606         case OP_IXOR:
10607                 return OP_X86_XOR_MEMBASE_REG;
10608         case OP_ADD_IMM:
10609         case OP_IADD_IMM:
10610                 return OP_X86_ADD_MEMBASE_IMM;
10611         case OP_SUB_IMM:
10612         case OP_ISUB_IMM:
10613                 return OP_X86_SUB_MEMBASE_IMM;
10614         case OP_AND_IMM:
10615         case OP_IAND_IMM:
10616                 return OP_X86_AND_MEMBASE_IMM;
10617         case OP_OR_IMM:
10618         case OP_IOR_IMM:
10619                 return OP_X86_OR_MEMBASE_IMM;
10620         case OP_XOR_IMM:
10621         case OP_IXOR_IMM:
10622                 return OP_X86_XOR_MEMBASE_IMM;
10623         case OP_MOVE:
10624                 return OP_NOP;
10625         }
10626 #endif
10627
10628 #if defined(TARGET_AMD64)
10629         if (!((store_opcode == OP_STORE_MEMBASE_REG) || (store_opcode == OP_STOREI4_MEMBASE_REG) || (store_opcode == OP_STOREI8_MEMBASE_REG)))
10630                 return -1;
10631
10632         switch (opcode) {
10633         case OP_IADD:
10634                 return OP_X86_ADD_MEMBASE_REG;
10635         case OP_ISUB:
10636                 return OP_X86_SUB_MEMBASE_REG;
10637         case OP_IAND:
10638                 return OP_X86_AND_MEMBASE_REG;
10639         case OP_IOR:
10640                 return OP_X86_OR_MEMBASE_REG;
10641         case OP_IXOR:
10642                 return OP_X86_XOR_MEMBASE_REG;
10643         case OP_IADD_IMM:
10644                 return OP_X86_ADD_MEMBASE_IMM;
10645         case OP_ISUB_IMM:
10646                 return OP_X86_SUB_MEMBASE_IMM;
10647         case OP_IAND_IMM:
10648                 return OP_X86_AND_MEMBASE_IMM;
10649         case OP_IOR_IMM:
10650                 return OP_X86_OR_MEMBASE_IMM;
10651         case OP_IXOR_IMM:
10652                 return OP_X86_XOR_MEMBASE_IMM;
10653         case OP_LADD:
10654                 return OP_AMD64_ADD_MEMBASE_REG;
10655         case OP_LSUB:
10656                 return OP_AMD64_SUB_MEMBASE_REG;
10657         case OP_LAND:
10658                 return OP_AMD64_AND_MEMBASE_REG;
10659         case OP_LOR:
10660                 return OP_AMD64_OR_MEMBASE_REG;
10661         case OP_LXOR:
10662                 return OP_AMD64_XOR_MEMBASE_REG;
10663         case OP_ADD_IMM:
10664         case OP_LADD_IMM:
10665                 return OP_AMD64_ADD_MEMBASE_IMM;
10666         case OP_SUB_IMM:
10667         case OP_LSUB_IMM:
10668                 return OP_AMD64_SUB_MEMBASE_IMM;
10669         case OP_AND_IMM:
10670         case OP_LAND_IMM:
10671                 return OP_AMD64_AND_MEMBASE_IMM;
10672         case OP_OR_IMM:
10673         case OP_LOR_IMM:
10674                 return OP_AMD64_OR_MEMBASE_IMM;
10675         case OP_XOR_IMM:
10676         case OP_LXOR_IMM:
10677                 return OP_AMD64_XOR_MEMBASE_IMM;
10678         case OP_MOVE:
10679                 return OP_NOP;
10680         }
10681 #endif
10682
10683         return -1;
10684 }
10685
10686 static inline int
10687 op_to_op_store_membase (int store_opcode, int opcode)
10688 {
10689 #if defined(TARGET_X86) || defined(TARGET_AMD64)
10690         switch (opcode) {
10691         case OP_ICEQ:
10692                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
10693                         return OP_X86_SETEQ_MEMBASE;
10694         case OP_CNE:
10695                 if (store_opcode == OP_STOREI1_MEMBASE_REG)
10696                         return OP_X86_SETNE_MEMBASE;
10697         }
10698 #endif
10699
10700         return -1;
10701 }
10702
10703 static inline int
10704 op_to_op_src1_membase (int load_opcode, int opcode)
10705 {
10706 #ifdef TARGET_X86
10707         /* FIXME: This has sign extension issues */
10708         /*
10709         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
10710                 return OP_X86_COMPARE_MEMBASE8_IMM;
10711         */
10712
10713         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
10714                 return -1;
10715
10716         switch (opcode) {
10717         case OP_X86_PUSH:
10718                 return OP_X86_PUSH_MEMBASE;
10719         case OP_COMPARE_IMM:
10720         case OP_ICOMPARE_IMM:
10721                 return OP_X86_COMPARE_MEMBASE_IMM;
10722         case OP_COMPARE:
10723         case OP_ICOMPARE:
10724                 return OP_X86_COMPARE_MEMBASE_REG;
10725         }
10726 #endif
10727
10728 #ifdef TARGET_AMD64
10729         /* FIXME: This has sign extension issues */
10730         /*
10731         if ((opcode == OP_ICOMPARE_IMM) && (load_opcode == OP_LOADU1_MEMBASE))
10732                 return OP_X86_COMPARE_MEMBASE8_IMM;
10733         */
10734
10735         switch (opcode) {
10736         case OP_X86_PUSH:
10737                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10738                         return OP_X86_PUSH_MEMBASE;
10739                 break;
10740                 /* FIXME: This only works for 32 bit immediates
10741         case OP_COMPARE_IMM:
10742         case OP_LCOMPARE_IMM:
10743                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10744                         return OP_AMD64_COMPARE_MEMBASE_IMM;
10745                 */
10746         case OP_ICOMPARE_IMM:
10747                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10748                         return OP_AMD64_ICOMPARE_MEMBASE_IMM;
10749                 break;
10750         case OP_COMPARE:
10751         case OP_LCOMPARE:
10752                 if ((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI8_MEMBASE))
10753                         return OP_AMD64_COMPARE_MEMBASE_REG;
10754                 break;
10755         case OP_ICOMPARE:
10756                 if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE))
10757                         return OP_AMD64_ICOMPARE_MEMBASE_REG;
10758                 break;
10759         }
10760 #endif
10761
10762         return -1;
10763 }
10764
10765 static inline int
10766 op_to_op_src2_membase (int load_opcode, int opcode)
10767 {
10768 #ifdef TARGET_X86
10769         if (!((load_opcode == OP_LOAD_MEMBASE) || (load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)))
10770                 return -1;
10771         
10772         switch (opcode) {
10773         case OP_COMPARE:
10774         case OP_ICOMPARE:
10775                 return OP_X86_COMPARE_REG_MEMBASE;
10776         case OP_IADD:
10777                 return OP_X86_ADD_REG_MEMBASE;
10778         case OP_ISUB:
10779                 return OP_X86_SUB_REG_MEMBASE;
10780         case OP_IAND:
10781                 return OP_X86_AND_REG_MEMBASE;
10782         case OP_IOR:
10783                 return OP_X86_OR_REG_MEMBASE;
10784         case OP_IXOR:
10785                 return OP_X86_XOR_REG_MEMBASE;
10786         }
10787 #endif
10788
10789 #ifdef TARGET_AMD64
10790         if ((load_opcode == OP_LOADI4_MEMBASE) || (load_opcode == OP_LOADU4_MEMBASE)) {
10791                 switch (opcode) {
10792                 case OP_ICOMPARE:
10793                         return OP_AMD64_ICOMPARE_REG_MEMBASE;
10794                 case OP_IADD:
10795                         return OP_X86_ADD_REG_MEMBASE;
10796                 case OP_ISUB:
10797                         return OP_X86_SUB_REG_MEMBASE;
10798                 case OP_IAND:
10799                         return OP_X86_AND_REG_MEMBASE;
10800                 case OP_IOR:
10801                         return OP_X86_OR_REG_MEMBASE;
10802                 case OP_IXOR:
10803                         return OP_X86_XOR_REG_MEMBASE;
10804                 }
10805         } else if ((load_opcode == OP_LOADI8_MEMBASE) || (load_opcode == OP_LOAD_MEMBASE)) {
10806                 switch (opcode) {
10807                 case OP_COMPARE:
10808                 case OP_LCOMPARE:
10809                         return OP_AMD64_COMPARE_REG_MEMBASE;
10810                 case OP_LADD:
10811                         return OP_AMD64_ADD_REG_MEMBASE;
10812                 case OP_LSUB:
10813                         return OP_AMD64_SUB_REG_MEMBASE;
10814                 case OP_LAND:
10815                         return OP_AMD64_AND_REG_MEMBASE;
10816                 case OP_LOR:
10817                         return OP_AMD64_OR_REG_MEMBASE;
10818                 case OP_LXOR:
10819                         return OP_AMD64_XOR_REG_MEMBASE;
10820                 }
10821         }
10822 #endif
10823
10824         return -1;
10825 }
10826
10827 int
10828 mono_op_to_op_imm_noemul (int opcode)
10829 {
10830         switch (opcode) {
10831 #if SIZEOF_REGISTER == 4 && !defined(MONO_ARCH_NO_EMULATE_LONG_SHIFT_OPS)
10832         case OP_LSHR:
10833         case OP_LSHL:
10834         case OP_LSHR_UN:
10835                 return -1;
10836 #endif
10837 #if defined(MONO_ARCH_EMULATE_MUL_DIV) || defined(MONO_ARCH_EMULATE_DIV)
10838         case OP_IDIV:
10839         case OP_IDIV_UN:
10840         case OP_IREM:
10841         case OP_IREM_UN:
10842                 return -1;
10843 #endif
10844         default:
10845                 return mono_op_to_op_imm (opcode);
10846         }
10847 }
10848
10849 #ifndef DISABLE_JIT
10850
10851 /**
10852  * mono_handle_global_vregs:
10853  *
10854  *   Make vregs used in more than one bblock 'global', i.e. allocate a variable
10855  * for them.
10856  */
10857 void
10858 mono_handle_global_vregs (MonoCompile *cfg)
10859 {
10860         gint32 *vreg_to_bb;
10861         MonoBasicBlock *bb;
10862         int i, pos;
10863
10864         vreg_to_bb = mono_mempool_alloc0 (cfg->mempool, sizeof (gint32*) * cfg->next_vreg + 1);
10865
10866 #ifdef MONO_ARCH_SIMD_INTRINSICS
10867         if (cfg->uses_simd_intrinsics)
10868                 mono_simd_simplify_indirection (cfg);
10869 #endif
10870
10871         /* Find local vregs used in more than one bb */
10872         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
10873                 MonoInst *ins = bb->code;       
10874                 int block_num = bb->block_num;
10875
10876                 if (cfg->verbose_level > 2)
10877                         printf ("\nHANDLE-GLOBAL-VREGS BLOCK %d:\n", bb->block_num);
10878
10879                 cfg->cbb = bb;
10880                 for (; ins; ins = ins->next) {
10881                         const char *spec = INS_INFO (ins->opcode);
10882                         int regtype = 0, regindex;
10883                         gint32 prev_bb;
10884
10885                         if (G_UNLIKELY (cfg->verbose_level > 2))
10886                                 mono_print_ins (ins);
10887
10888                         g_assert (ins->opcode >= MONO_CEE_LAST);
10889
10890                         for (regindex = 0; regindex < 4; regindex ++) {
10891                                 int vreg = 0;
10892
10893                                 if (regindex == 0) {
10894                                         regtype = spec [MONO_INST_DEST];
10895                                         if (regtype == ' ')
10896                                                 continue;
10897                                         vreg = ins->dreg;
10898                                 } else if (regindex == 1) {
10899                                         regtype = spec [MONO_INST_SRC1];
10900                                         if (regtype == ' ')
10901                                                 continue;
10902                                         vreg = ins->sreg1;
10903                                 } else if (regindex == 2) {
10904                                         regtype = spec [MONO_INST_SRC2];
10905                                         if (regtype == ' ')
10906                                                 continue;
10907                                         vreg = ins->sreg2;
10908                                 } else if (regindex == 3) {
10909                                         regtype = spec [MONO_INST_SRC3];
10910                                         if (regtype == ' ')
10911                                                 continue;
10912                                         vreg = ins->sreg3;
10913                                 }
10914
10915 #if SIZEOF_REGISTER == 4
10916                                 /* In the LLVM case, the long opcodes are not decomposed */
10917                                 if (regtype == 'l' && !COMPILE_LLVM (cfg)) {
10918                                         /*
10919                                          * Since some instructions reference the original long vreg,
10920                                          * and some reference the two component vregs, it is quite hard
10921                                          * to determine when it needs to be global. So be conservative.
10922                                          */
10923                                         if (!get_vreg_to_inst (cfg, vreg)) {
10924                                                 mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
10925
10926                                                 if (cfg->verbose_level > 2)
10927                                                         printf ("LONG VREG R%d made global.\n", vreg);
10928                                         }
10929
10930                                         /*
10931                                          * Make the component vregs volatile since the optimizations can
10932                                          * get confused otherwise.
10933                                          */
10934                                         get_vreg_to_inst (cfg, vreg + 1)->flags |= MONO_INST_VOLATILE;
10935                                         get_vreg_to_inst (cfg, vreg + 2)->flags |= MONO_INST_VOLATILE;
10936                                 }
10937 #endif
10938
10939                                 g_assert (vreg != -1);
10940
10941                                 prev_bb = vreg_to_bb [vreg];
10942                                 if (prev_bb == 0) {
10943                                         /* 0 is a valid block num */
10944                                         vreg_to_bb [vreg] = block_num + 1;
10945                                 } else if ((prev_bb != block_num + 1) && (prev_bb != -1)) {
10946                                         if (((regtype == 'i' && (vreg < MONO_MAX_IREGS))) || (regtype == 'f' && (vreg < MONO_MAX_FREGS)))
10947                                                 continue;
10948
10949                                         if (!get_vreg_to_inst (cfg, vreg)) {
10950                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
10951                                                         printf ("VREG R%d used in BB%d and BB%d made global.\n", vreg, vreg_to_bb [vreg], block_num);
10952
10953                                                 switch (regtype) {
10954                                                 case 'i':
10955                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL, vreg);
10956                                                         break;
10957                                                 case 'l':
10958                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.int64_class->byval_arg, OP_LOCAL, vreg);
10959                                                         break;
10960                                                 case 'f':
10961                                                         mono_compile_create_var_for_vreg (cfg, &mono_defaults.double_class->byval_arg, OP_LOCAL, vreg);
10962                                                         break;
10963                                                 case 'v':
10964                                                         mono_compile_create_var_for_vreg (cfg, &ins->klass->byval_arg, OP_LOCAL, vreg);
10965                                                         break;
10966                                                 default:
10967                                                         g_assert_not_reached ();
10968                                                 }
10969                                         }
10970
10971                                         /* Flag as having been used in more than one bb */
10972                                         vreg_to_bb [vreg] = -1;
10973                                 }
10974                         }
10975                 }
10976         }
10977
10978         /* If a variable is used in only one bblock, convert it into a local vreg */
10979         for (i = 0; i < cfg->num_varinfo; i++) {
10980                 MonoInst *var = cfg->varinfo [i];
10981                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
10982
10983                 switch (var->type) {
10984                 case STACK_I4:
10985                 case STACK_OBJ:
10986                 case STACK_PTR:
10987                 case STACK_MP:
10988                 case STACK_VTYPE:
10989 #if SIZEOF_REGISTER == 8
10990                 case STACK_I8:
10991 #endif
10992 #if !defined(TARGET_X86) && !defined(MONO_ARCH_SOFT_FLOAT)
10993                 /* Enabling this screws up the fp stack on x86 */
10994                 case STACK_R8:
10995 #endif
10996                         /* Arguments are implicitly global */
10997                         /* Putting R4 vars into registers doesn't work currently */
10998                         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) {
10999                                 /* 
11000                                  * Make that the variable's liveness interval doesn't contain a call, since
11001                                  * that would cause the lvreg to be spilled, making the whole optimization
11002                                  * useless.
11003                                  */
11004                                 /* This is too slow for JIT compilation */
11005 #if 0
11006                                 if (cfg->compile_aot && vreg_to_bb [var->dreg]) {
11007                                         MonoInst *ins;
11008                                         int def_index, call_index, ins_index;
11009                                         gboolean spilled = FALSE;
11010
11011                                         def_index = -1;
11012                                         call_index = -1;
11013                                         ins_index = 0;
11014                                         for (ins = vreg_to_bb [var->dreg]->code; ins; ins = ins->next) {
11015                                                 const char *spec = INS_INFO (ins->opcode);
11016
11017                                                 if ((spec [MONO_INST_DEST] != ' ') && (ins->dreg == var->dreg))
11018                                                         def_index = ins_index;
11019
11020                                                 if (((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg)) ||
11021                                                         ((spec [MONO_INST_SRC1] != ' ') && (ins->sreg1 == var->dreg))) {
11022                                                         if (call_index > def_index) {
11023                                                                 spilled = TRUE;
11024                                                                 break;
11025                                                         }
11026                                                 }
11027
11028                                                 if (MONO_IS_CALL (ins))
11029                                                         call_index = ins_index;
11030
11031                                                 ins_index ++;
11032                                         }
11033
11034                                         if (spilled)
11035                                                 break;
11036                                 }
11037 #endif
11038
11039                                 if (G_UNLIKELY (cfg->verbose_level > 2))
11040                                         printf ("CONVERTED R%d(%d) TO VREG.\n", var->dreg, vmv->idx);
11041                                 var->flags |= MONO_INST_IS_DEAD;
11042                                 cfg->vreg_to_inst [var->dreg] = NULL;
11043                         }
11044                         break;
11045                 }
11046         }
11047
11048         /* 
11049          * Compress the varinfo and vars tables so the liveness computation is faster and
11050          * takes up less space.
11051          */
11052         pos = 0;
11053         for (i = 0; i < cfg->num_varinfo; ++i) {
11054                 MonoInst *var = cfg->varinfo [i];
11055                 if (pos < i && cfg->locals_start == i)
11056                         cfg->locals_start = pos;
11057                 if (!(var->flags & MONO_INST_IS_DEAD)) {
11058                         if (pos < i) {
11059                                 cfg->varinfo [pos] = cfg->varinfo [i];
11060                                 cfg->varinfo [pos]->inst_c0 = pos;
11061                                 memcpy (&cfg->vars [pos], &cfg->vars [i], sizeof (MonoMethodVar));
11062                                 cfg->vars [pos].idx = pos;
11063 #if SIZEOF_REGISTER == 4
11064                                 if (cfg->varinfo [pos]->type == STACK_I8) {
11065                                         /* Modify the two component vars too */
11066                                         MonoInst *var1;
11067
11068                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 1);
11069                                         var1->inst_c0 = pos;
11070                                         var1 = get_vreg_to_inst (cfg, cfg->varinfo [pos]->dreg + 2);
11071                                         var1->inst_c0 = pos;
11072                                 }
11073 #endif
11074                         }
11075                         pos ++;
11076                 }
11077         }
11078         cfg->num_varinfo = pos;
11079         if (cfg->locals_start > cfg->num_varinfo)
11080                 cfg->locals_start = cfg->num_varinfo;
11081 }
11082
11083 /**
11084  * mono_spill_global_vars:
11085  *
11086  *   Generate spill code for variables which are not allocated to registers, 
11087  * and replace vregs with their allocated hregs. *need_local_opts is set to TRUE if
11088  * code is generated which could be optimized by the local optimization passes.
11089  */
11090 void
11091 mono_spill_global_vars (MonoCompile *cfg, gboolean *need_local_opts)
11092 {
11093         MonoBasicBlock *bb;
11094         char spec2 [16];
11095         int orig_next_vreg;
11096         guint32 *vreg_to_lvreg;
11097         guint32 *lvregs;
11098         guint32 i, lvregs_len;
11099         gboolean dest_has_lvreg = FALSE;
11100         guint32 stacktypes [128];
11101         MonoInst **live_range_start, **live_range_end;
11102         MonoBasicBlock **live_range_start_bb, **live_range_end_bb;
11103
11104         *need_local_opts = FALSE;
11105
11106         memset (spec2, 0, sizeof (spec2));
11107
11108         /* FIXME: Move this function to mini.c */
11109         stacktypes ['i'] = STACK_PTR;
11110         stacktypes ['l'] = STACK_I8;
11111         stacktypes ['f'] = STACK_R8;
11112 #ifdef MONO_ARCH_SIMD_INTRINSICS
11113         stacktypes ['x'] = STACK_VTYPE;
11114 #endif
11115
11116 #if SIZEOF_REGISTER == 4
11117         /* Create MonoInsts for longs */
11118         for (i = 0; i < cfg->num_varinfo; i++) {
11119                 MonoInst *ins = cfg->varinfo [i];
11120
11121                 if ((ins->opcode != OP_REGVAR) && !(ins->flags & MONO_INST_IS_DEAD)) {
11122                         switch (ins->type) {
11123                         case STACK_R8:
11124                         case STACK_I8: {
11125                                 MonoInst *tree;
11126
11127                                 if (ins->type == STACK_R8 && !COMPILE_SOFT_FLOAT (cfg))
11128                                         break;
11129
11130                                 g_assert (ins->opcode == OP_REGOFFSET);
11131
11132                                 tree = get_vreg_to_inst (cfg, ins->dreg + 1);
11133                                 g_assert (tree);
11134                                 tree->opcode = OP_REGOFFSET;
11135                                 tree->inst_basereg = ins->inst_basereg;
11136                                 tree->inst_offset = ins->inst_offset + MINI_LS_WORD_OFFSET;
11137
11138                                 tree = get_vreg_to_inst (cfg, ins->dreg + 2);
11139                                 g_assert (tree);
11140                                 tree->opcode = OP_REGOFFSET;
11141                                 tree->inst_basereg = ins->inst_basereg;
11142                                 tree->inst_offset = ins->inst_offset + MINI_MS_WORD_OFFSET;
11143                                 break;
11144                         }
11145                         default:
11146                                 break;
11147                         }
11148                 }
11149         }
11150 #endif
11151
11152         /* FIXME: widening and truncation */
11153
11154         /*
11155          * As an optimization, when a variable allocated to the stack is first loaded into 
11156          * an lvreg, we will remember the lvreg and use it the next time instead of loading
11157          * the variable again.
11158          */
11159         orig_next_vreg = cfg->next_vreg;
11160         vreg_to_lvreg = mono_mempool_alloc0 (cfg->mempool, sizeof (guint32) * cfg->next_vreg);
11161         lvregs = mono_mempool_alloc (cfg->mempool, sizeof (guint32) * 1024);
11162         lvregs_len = 0;
11163
11164         /* 
11165          * These arrays contain the first and last instructions accessing a given
11166          * variable.
11167          * Since we emit bblocks in the same order we process them here, and we
11168          * don't split live ranges, these will precisely describe the live range of
11169          * the variable, i.e. the instruction range where a valid value can be found
11170          * in the variables location.
11171          * The live range is computed using the liveness info computed by the liveness pass.
11172          * We can't use vmv->range, since that is an abstract live range, and we need
11173          * one which is instruction precise.
11174          * FIXME: Variables used in out-of-line bblocks have a hole in their live range.
11175          */
11176         /* FIXME: Only do this if debugging info is requested */
11177         live_range_start = g_new0 (MonoInst*, cfg->next_vreg);
11178         live_range_end = g_new0 (MonoInst*, cfg->next_vreg);
11179         live_range_start_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
11180         live_range_end_bb = g_new (MonoBasicBlock*, cfg->next_vreg);
11181         
11182         /* Add spill loads/stores */
11183         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
11184                 MonoInst *ins;
11185
11186                 if (cfg->verbose_level > 2)
11187                         printf ("\nSPILL BLOCK %d:\n", bb->block_num);
11188
11189                 /* Clear vreg_to_lvreg array */
11190                 for (i = 0; i < lvregs_len; i++)
11191                         vreg_to_lvreg [lvregs [i]] = 0;
11192                 lvregs_len = 0;
11193
11194                 cfg->cbb = bb;
11195                 MONO_BB_FOR_EACH_INS (bb, ins) {
11196                         const char *spec = INS_INFO (ins->opcode);
11197                         int regtype, srcindex, sreg, tmp_reg, prev_dreg, num_sregs;
11198                         gboolean store, no_lvreg;
11199                         int sregs [MONO_MAX_SRC_REGS];
11200
11201                         if (G_UNLIKELY (cfg->verbose_level > 2))
11202                                 mono_print_ins (ins);
11203
11204                         if (ins->opcode == OP_NOP)
11205                                 continue;
11206
11207                         /* 
11208                          * We handle LDADDR here as well, since it can only be decomposed
11209                          * when variable addresses are known.
11210                          */
11211                         if (ins->opcode == OP_LDADDR) {
11212                                 MonoInst *var = ins->inst_p0;
11213
11214                                 if (var->opcode == OP_VTARG_ADDR) {
11215                                         /* Happens on SPARC/S390 where vtypes are passed by reference */
11216                                         MonoInst *vtaddr = var->inst_left;
11217                                         if (vtaddr->opcode == OP_REGVAR) {
11218                                                 ins->opcode = OP_MOVE;
11219                                                 ins->sreg1 = vtaddr->dreg;
11220                                         }
11221                                         else if (var->inst_left->opcode == OP_REGOFFSET) {
11222                                                 ins->opcode = OP_LOAD_MEMBASE;
11223                                                 ins->inst_basereg = vtaddr->inst_basereg;
11224                                                 ins->inst_offset = vtaddr->inst_offset;
11225                                         } else
11226                                                 NOT_IMPLEMENTED;
11227                                 } else {
11228                                         g_assert (var->opcode == OP_REGOFFSET);
11229
11230                                         ins->opcode = OP_ADD_IMM;
11231                                         ins->sreg1 = var->inst_basereg;
11232                                         ins->inst_imm = var->inst_offset;
11233                                 }
11234
11235                                 *need_local_opts = TRUE;
11236                                 spec = INS_INFO (ins->opcode);
11237                         }
11238
11239                         if (ins->opcode < MONO_CEE_LAST) {
11240                                 mono_print_ins (ins);
11241                                 g_assert_not_reached ();
11242                         }
11243
11244                         /*
11245                          * Store opcodes have destbasereg in the dreg, but in reality, it is an
11246                          * src register.
11247                          * FIXME:
11248                          */
11249                         if (MONO_IS_STORE_MEMBASE (ins)) {
11250                                 tmp_reg = ins->dreg;
11251                                 ins->dreg = ins->sreg2;
11252                                 ins->sreg2 = tmp_reg;
11253                                 store = TRUE;
11254
11255                                 spec2 [MONO_INST_DEST] = ' ';
11256                                 spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
11257                                 spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
11258                                 spec2 [MONO_INST_SRC3] = ' ';
11259                                 spec = spec2;
11260                         } else if (MONO_IS_STORE_MEMINDEX (ins))
11261                                 g_assert_not_reached ();
11262                         else
11263                                 store = FALSE;
11264                         no_lvreg = FALSE;
11265
11266                         if (G_UNLIKELY (cfg->verbose_level > 2)) {
11267                                 printf ("\t %.3s %d", spec, ins->dreg);
11268                                 num_sregs = mono_inst_get_src_registers (ins, sregs);
11269                                 for (srcindex = 0; srcindex < 3; ++srcindex)
11270                                         printf (" %d", sregs [srcindex]);
11271                                 printf ("\n");
11272                         }
11273
11274                         /***************/
11275                         /*    DREG     */
11276                         /***************/
11277                         regtype = spec [MONO_INST_DEST];
11278                         g_assert (((ins->dreg == -1) && (regtype == ' ')) || ((ins->dreg != -1) && (regtype != ' ')));
11279                         prev_dreg = -1;
11280
11281                         if ((ins->dreg != -1) && get_vreg_to_inst (cfg, ins->dreg)) {
11282                                 MonoInst *var = get_vreg_to_inst (cfg, ins->dreg);
11283                                 MonoInst *store_ins;
11284                                 int store_opcode;
11285                                 MonoInst *def_ins = ins;
11286                                 int dreg = ins->dreg; /* The original vreg */
11287
11288                                 store_opcode = mono_type_to_store_membase (cfg, var->inst_vtype);
11289
11290                                 if (var->opcode == OP_REGVAR) {
11291                                         ins->dreg = var->dreg;
11292                                 } 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)) {
11293                                         /* 
11294                                          * Instead of emitting a load+store, use a _membase opcode.
11295                                          */
11296                                         g_assert (var->opcode == OP_REGOFFSET);
11297                                         if (ins->opcode == OP_MOVE) {
11298                                                 NULLIFY_INS (ins);
11299                                                 def_ins = NULL;
11300                                         } else {
11301                                                 ins->opcode = op_to_op_dest_membase (store_opcode, ins->opcode);
11302                                                 ins->inst_basereg = var->inst_basereg;
11303                                                 ins->inst_offset = var->inst_offset;
11304                                                 ins->dreg = -1;
11305                                         }
11306                                         spec = INS_INFO (ins->opcode);
11307                                 } else {
11308                                         guint32 lvreg;
11309
11310                                         g_assert (var->opcode == OP_REGOFFSET);
11311
11312                                         prev_dreg = ins->dreg;
11313
11314                                         /* Invalidate any previous lvreg for this vreg */
11315                                         vreg_to_lvreg [ins->dreg] = 0;
11316
11317                                         lvreg = 0;
11318
11319                                         if (COMPILE_SOFT_FLOAT (cfg) && store_opcode == OP_STORER8_MEMBASE_REG) {
11320                                                 regtype = 'l';
11321                                                 store_opcode = OP_STOREI8_MEMBASE_REG;
11322                                         }
11323
11324                                         ins->dreg = alloc_dreg (cfg, stacktypes [regtype]);
11325
11326                                         if (regtype == 'l') {
11327                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET, ins->dreg + 1);
11328                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
11329                                                 NEW_STORE_MEMBASE (cfg, store_ins, OP_STOREI4_MEMBASE_REG, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET, ins->dreg + 2);
11330                                                 mono_bblock_insert_after_ins (bb, ins, store_ins);
11331                                                 def_ins = store_ins;
11332                                         }
11333                                         else {
11334                                                 g_assert (store_opcode != OP_STOREV_MEMBASE);
11335
11336                                                 /* Try to fuse the store into the instruction itself */
11337                                                 /* FIXME: Add more instructions */
11338                                                 if (!lvreg && ((ins->opcode == OP_ICONST) || ((ins->opcode == OP_I8CONST) && (ins->inst_c0 == 0)))) {
11339                                                         ins->opcode = store_membase_reg_to_store_membase_imm (store_opcode);
11340                                                         ins->inst_imm = ins->inst_c0;
11341                                                         ins->inst_destbasereg = var->inst_basereg;
11342                                                         ins->inst_offset = var->inst_offset;
11343                                                         spec = INS_INFO (ins->opcode);
11344                                                 } else if (!lvreg && ((ins->opcode == OP_MOVE) || (ins->opcode == OP_FMOVE) || (ins->opcode == OP_LMOVE))) {
11345                                                         ins->opcode = store_opcode;
11346                                                         ins->inst_destbasereg = var->inst_basereg;
11347                                                         ins->inst_offset = var->inst_offset;
11348
11349                                                         no_lvreg = TRUE;
11350
11351                                                         tmp_reg = ins->dreg;
11352                                                         ins->dreg = ins->sreg2;
11353                                                         ins->sreg2 = tmp_reg;
11354                                                         store = TRUE;
11355
11356                                                         spec2 [MONO_INST_DEST] = ' ';
11357                                                         spec2 [MONO_INST_SRC1] = spec [MONO_INST_SRC1];
11358                                                         spec2 [MONO_INST_SRC2] = spec [MONO_INST_DEST];
11359                                                         spec2 [MONO_INST_SRC3] = ' ';
11360                                                         spec = spec2;
11361                                                 } else if (!lvreg && (op_to_op_store_membase (store_opcode, ins->opcode) != -1)) {
11362                                                         // FIXME: The backends expect the base reg to be in inst_basereg
11363                                                         ins->opcode = op_to_op_store_membase (store_opcode, ins->opcode);
11364                                                         ins->dreg = -1;
11365                                                         ins->inst_basereg = var->inst_basereg;
11366                                                         ins->inst_offset = var->inst_offset;
11367                                                         spec = INS_INFO (ins->opcode);
11368                                                 } else {
11369                                                         /* printf ("INS: "); mono_print_ins (ins); */
11370                                                         /* Create a store instruction */
11371                                                         NEW_STORE_MEMBASE (cfg, store_ins, store_opcode, var->inst_basereg, var->inst_offset, ins->dreg);
11372
11373                                                         /* Insert it after the instruction */
11374                                                         mono_bblock_insert_after_ins (bb, ins, store_ins);
11375
11376                                                         def_ins = store_ins;
11377
11378                                                         /* 
11379                                                          * We can't assign ins->dreg to var->dreg here, since the
11380                                                          * sregs could use it. So set a flag, and do it after
11381                                                          * the sregs.
11382                                                          */
11383                                                         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)))
11384                                                                 dest_has_lvreg = TRUE;
11385                                                 }
11386                                         }
11387                                 }
11388
11389                                 if (def_ins && !live_range_start [dreg]) {
11390                                         live_range_start [dreg] = def_ins;
11391                                         live_range_start_bb [dreg] = bb;
11392                                 }
11393                         }
11394
11395                         /************/
11396                         /*  SREGS   */
11397                         /************/
11398                         num_sregs = mono_inst_get_src_registers (ins, sregs);
11399                         for (srcindex = 0; srcindex < 3; ++srcindex) {
11400                                 regtype = spec [MONO_INST_SRC1 + srcindex];
11401                                 sreg = sregs [srcindex];
11402
11403                                 g_assert (((sreg == -1) && (regtype == ' ')) || ((sreg != -1) && (regtype != ' ')));
11404                                 if ((sreg != -1) && get_vreg_to_inst (cfg, sreg)) {
11405                                         MonoInst *var = get_vreg_to_inst (cfg, sreg);
11406                                         MonoInst *use_ins = ins;
11407                                         MonoInst *load_ins;
11408                                         guint32 load_opcode;
11409
11410                                         if (var->opcode == OP_REGVAR) {
11411                                                 sregs [srcindex] = var->dreg;
11412                                                 //mono_inst_set_src_registers (ins, sregs);
11413                                                 live_range_end [sreg] = use_ins;
11414                                                 live_range_end_bb [sreg] = bb;
11415                                                 continue;
11416                                         }
11417
11418                                         g_assert (var->opcode == OP_REGOFFSET);
11419                                                 
11420                                         load_opcode = mono_type_to_load_membase (cfg, var->inst_vtype);
11421
11422                                         g_assert (load_opcode != OP_LOADV_MEMBASE);
11423
11424                                         if (vreg_to_lvreg [sreg]) {
11425                                                 g_assert (vreg_to_lvreg [sreg] != -1);
11426
11427                                                 /* The variable is already loaded to an lvreg */
11428                                                 if (G_UNLIKELY (cfg->verbose_level > 2))
11429                                                         printf ("\t\tUse lvreg R%d for R%d.\n", vreg_to_lvreg [sreg], sreg);
11430                                                 sregs [srcindex] = vreg_to_lvreg [sreg];
11431                                                 //mono_inst_set_src_registers (ins, sregs);
11432                                                 continue;
11433                                         }
11434
11435                                         /* Try to fuse the load into the instruction */
11436                                         if ((srcindex == 0) && (op_to_op_src1_membase (load_opcode, ins->opcode) != -1)) {
11437                                                 ins->opcode = op_to_op_src1_membase (load_opcode, ins->opcode);
11438                                                 sregs [0] = var->inst_basereg;
11439                                                 //mono_inst_set_src_registers (ins, sregs);
11440                                                 ins->inst_offset = var->inst_offset;
11441                                         } else if ((srcindex == 1) && (op_to_op_src2_membase (load_opcode, ins->opcode) != -1)) {
11442                                                 ins->opcode = op_to_op_src2_membase (load_opcode, ins->opcode);
11443                                                 sregs [1] = var->inst_basereg;
11444                                                 //mono_inst_set_src_registers (ins, sregs);
11445                                                 ins->inst_offset = var->inst_offset;
11446                                         } else {
11447                                                 if (MONO_IS_REAL_MOVE (ins)) {
11448                                                         ins->opcode = OP_NOP;
11449                                                         sreg = ins->dreg;
11450                                                 } else {
11451                                                         //printf ("%d ", srcindex); mono_print_ins (ins);
11452
11453                                                         sreg = alloc_dreg (cfg, stacktypes [regtype]);
11454
11455                                                         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) {
11456                                                                 if (var->dreg == prev_dreg) {
11457                                                                         /*
11458                                                                          * sreg refers to the value loaded by the load
11459                                                                          * emitted below, but we need to use ins->dreg
11460                                                                          * since it refers to the store emitted earlier.
11461                                                                          */
11462                                                                         sreg = ins->dreg;
11463                                                                 }
11464                                                                 g_assert (sreg != -1);
11465                                                                 vreg_to_lvreg [var->dreg] = sreg;
11466                                                                 g_assert (lvregs_len < 1024);
11467                                                                 lvregs [lvregs_len ++] = var->dreg;
11468                                                         }
11469                                                 }
11470
11471                                                 sregs [srcindex] = sreg;
11472                                                 //mono_inst_set_src_registers (ins, sregs);
11473
11474                                                 if (regtype == 'l') {
11475                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 2, var->inst_basereg, var->inst_offset + MINI_MS_WORD_OFFSET);
11476                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11477                                                         NEW_LOAD_MEMBASE (cfg, load_ins, OP_LOADI4_MEMBASE, sreg + 1, var->inst_basereg, var->inst_offset + MINI_LS_WORD_OFFSET);
11478                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11479                                                         use_ins = load_ins;
11480                                                 }
11481                                                 else {
11482 #if SIZEOF_REGISTER == 4
11483                                                         g_assert (load_opcode != OP_LOADI8_MEMBASE);
11484 #endif
11485                                                         NEW_LOAD_MEMBASE (cfg, load_ins, load_opcode, sreg, var->inst_basereg, var->inst_offset);
11486                                                         mono_bblock_insert_before_ins (bb, ins, load_ins);
11487                                                         use_ins = load_ins;
11488                                                 }
11489                                         }
11490
11491                                         if (var->dreg < orig_next_vreg) {
11492                                                 live_range_end [var->dreg] = use_ins;
11493                                                 live_range_end_bb [var->dreg] = bb;
11494                                         }
11495                                 }
11496                         }
11497                         mono_inst_set_src_registers (ins, sregs);
11498
11499                         if (dest_has_lvreg) {
11500                                 g_assert (ins->dreg != -1);
11501                                 vreg_to_lvreg [prev_dreg] = ins->dreg;
11502                                 g_assert (lvregs_len < 1024);
11503                                 lvregs [lvregs_len ++] = prev_dreg;
11504                                 dest_has_lvreg = FALSE;
11505                         }
11506
11507                         if (store) {
11508                                 tmp_reg = ins->dreg;
11509                                 ins->dreg = ins->sreg2;
11510                                 ins->sreg2 = tmp_reg;
11511                         }
11512
11513                         if (MONO_IS_CALL (ins)) {
11514                                 /* Clear vreg_to_lvreg array */
11515                                 for (i = 0; i < lvregs_len; i++)
11516                                         vreg_to_lvreg [lvregs [i]] = 0;
11517                                 lvregs_len = 0;
11518                         } else if (ins->opcode == OP_NOP) {
11519                                 ins->dreg = -1;
11520                                 MONO_INST_NULLIFY_SREGS (ins);
11521                         }
11522
11523                         if (cfg->verbose_level > 2)
11524                                 mono_print_ins_index (1, ins);
11525                 }
11526
11527                 /* Extend the live range based on the liveness info */
11528                 if (cfg->compute_precise_live_ranges && bb->live_out_set && bb->code) {
11529                         for (i = 0; i < cfg->num_varinfo; i ++) {
11530                                 MonoMethodVar *vi = MONO_VARINFO (cfg, i);
11531
11532                                 if (vreg_is_volatile (cfg, vi->vreg))
11533                                         /* The liveness info is incomplete */
11534                                         continue;
11535
11536                                 if (mono_bitset_test_fast (bb->live_in_set, i) && !live_range_start [vi->vreg]) {
11537                                         /* Live from at least the first ins of this bb */
11538                                         live_range_start [vi->vreg] = bb->code;
11539                                         live_range_start_bb [vi->vreg] = bb;
11540                                 }
11541
11542                                 if (mono_bitset_test_fast (bb->live_out_set, i)) {
11543                                         /* Live at least until the last ins of this bb */
11544                                         live_range_end [vi->vreg] = bb->last_ins;
11545                                         live_range_end_bb [vi->vreg] = bb;
11546                                 }
11547                         }
11548                 }
11549         }
11550         
11551 #ifdef MONO_ARCH_HAVE_LIVERANGE_OPS
11552         /*
11553          * Emit LIVERANGE_START/LIVERANGE_END opcodes, the backend will implement them
11554          * by storing the current native offset into MonoMethodVar->live_range_start/end.
11555          */
11556         if (cfg->compute_precise_live_ranges && cfg->comp_done & MONO_COMP_LIVENESS) {
11557                 for (i = 0; i < cfg->num_varinfo; ++i) {
11558                         int vreg = MONO_VARINFO (cfg, i)->vreg;
11559                         MonoInst *ins;
11560
11561                         if (live_range_start [vreg]) {
11562                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_START);
11563                                 ins->inst_c0 = i;
11564                                 ins->inst_c1 = vreg;
11565                                 mono_bblock_insert_after_ins (live_range_start_bb [vreg], live_range_start [vreg], ins);
11566                         }
11567                         if (live_range_end [vreg]) {
11568                                 MONO_INST_NEW (cfg, ins, OP_LIVERANGE_END);
11569                                 ins->inst_c0 = i;
11570                                 ins->inst_c1 = vreg;
11571                                 if (live_range_end [vreg] == live_range_end_bb [vreg]->last_ins)
11572                                         mono_add_ins_to_end (live_range_end_bb [vreg], ins);
11573                                 else
11574                                         mono_bblock_insert_after_ins (live_range_end_bb [vreg], live_range_end [vreg], ins);
11575                         }
11576                 }
11577         }
11578 #endif
11579
11580         g_free (live_range_start);
11581         g_free (live_range_end);
11582         g_free (live_range_start_bb);
11583         g_free (live_range_end_bb);
11584 }
11585
11586 void
11587 mono_create_helper_signatures (void)
11588 {
11589         helper_sig_domain_get = mono_create_icall_signature ("ptr");
11590         helper_sig_class_init_trampoline = mono_create_icall_signature ("void");
11591         helper_sig_generic_class_init_trampoline = mono_create_icall_signature ("void");
11592         helper_sig_generic_class_init_trampoline_llvm = mono_create_icall_signature ("void ptr");
11593         helper_sig_rgctx_lazy_fetch_trampoline = mono_create_icall_signature ("ptr ptr");
11594         helper_sig_monitor_enter_exit_trampoline = mono_create_icall_signature ("void");
11595         helper_sig_monitor_enter_exit_trampoline_llvm = mono_create_icall_signature ("void object");
11596 }
11597
11598 /**
11599  * FIXME:
11600  * - use 'iadd' instead of 'int_add'
11601  * - handling ovf opcodes: decompose in method_to_ir.
11602  * - unify iregs/fregs
11603  *   -> partly done, the missing parts are:
11604  *   - a more complete unification would involve unifying the hregs as well, so
11605  *     code wouldn't need if (fp) all over the place. but that would mean the hregs
11606  *     would no longer map to the machine hregs, so the code generators would need to
11607  *     be modified. Also, on ia64 for example, niregs + nfregs > 256 -> bitmasks
11608  *     wouldn't work any more. Duplicating the code in mono_local_regalloc () into
11609  *     fp/non-fp branches speeds it up by about 15%.
11610  * - use sext/zext opcodes instead of shifts
11611  * - add OP_ICALL
11612  * - get rid of TEMPLOADs if possible and use vregs instead
11613  * - clean up usage of OP_P/OP_ opcodes
11614  * - cleanup usage of DUMMY_USE
11615  * - cleanup the setting of ins->type for MonoInst's which are pushed on the 
11616  *   stack
11617  * - set the stack type and allocate a dreg in the EMIT_NEW macros
11618  * - get rid of all the <foo>2 stuff when the new JIT is ready.
11619  * - make sure handle_stack_args () is called before the branch is emitted
11620  * - when the new IR is done, get rid of all unused stuff
11621  * - COMPARE/BEQ as separate instructions or unify them ?
11622  *   - keeping them separate allows specialized compare instructions like
11623  *     compare_imm, compare_membase
11624  *   - most back ends unify fp compare+branch, fp compare+ceq
11625  * - integrate mono_save_args into inline_method
11626  * - get rid of the empty bblocks created by MONO_EMIT_NEW_BRACH_BLOCK2
11627  * - handle long shift opts on 32 bit platforms somehow: they require 
11628  *   3 sregs (2 for arg1 and 1 for arg2)
11629  * - make byref a 'normal' type.
11630  * - use vregs for bb->out_stacks if possible, handle_global_vreg will make them a
11631  *   variable if needed.
11632  * - do not start a new IL level bblock when cfg->cbb is changed by a function call
11633  *   like inline_method.
11634  * - remove inlining restrictions
11635  * - fix LNEG and enable cfold of INEG
11636  * - generalize x86 optimizations like ldelema as a peephole optimization
11637  * - add store_mem_imm for amd64
11638  * - optimize the loading of the interruption flag in the managed->native wrappers
11639  * - avoid special handling of OP_NOP in passes
11640  * - move code inserting instructions into one function/macro.
11641  * - try a coalescing phase after liveness analysis
11642  * - add float -> vreg conversion + local optimizations on !x86
11643  * - figure out how to handle decomposed branches during optimizations, ie.
11644  *   compare+branch, op_jump_table+op_br etc.
11645  * - promote RuntimeXHandles to vregs
11646  * - vtype cleanups:
11647  *   - add a NEW_VARLOADA_VREG macro
11648  * - the vtype optimizations are blocked by the LDADDR opcodes generated for 
11649  *   accessing vtype fields.
11650  * - get rid of I8CONST on 64 bit platforms
11651  * - dealing with the increase in code size due to branches created during opcode
11652  *   decomposition:
11653  *   - use extended basic blocks
11654  *     - all parts of the JIT
11655  *     - handle_global_vregs () && local regalloc
11656  *   - avoid introducing global vregs during decomposition, like 'vtable' in isinst
11657  * - sources of increase in code size:
11658  *   - vtypes
11659  *   - long compares
11660  *   - isinst and castclass
11661  *   - lvregs not allocated to global registers even if used multiple times
11662  * - call cctors outside the JIT, to make -v output more readable and JIT timings more
11663  *   meaningful.
11664  * - check for fp stack leakage in other opcodes too. (-> 'exceptions' optimization)
11665  * - add all micro optimizations from the old JIT
11666  * - put tree optimizations into the deadce pass
11667  * - decompose op_start_handler/op_endfilter/op_endfinally earlier using an arch
11668  *   specific function.
11669  * - unify the float comparison opcodes with the other comparison opcodes, i.e.
11670  *   fcompare + branchCC.
11671  * - create a helper function for allocating a stack slot, taking into account 
11672  *   MONO_CFG_HAS_SPILLUP.
11673  * - merge r68207.
11674  * - merge the ia64 switch changes.
11675  * - optimize mono_regstate2_alloc_int/float.
11676  * - fix the pessimistic handling of variables accessed in exception handler blocks.
11677  * - need to write a tree optimization pass, but the creation of trees is difficult, i.e.
11678  *   parts of the tree could be separated by other instructions, killing the tree
11679  *   arguments, or stores killing loads etc. Also, should we fold loads into other
11680  *   instructions if the result of the load is used multiple times ?
11681  * - make the REM_IMM optimization in mini-x86.c arch-independent.
11682  * - LAST MERGE: 108395.
11683  * - when returning vtypes in registers, generate IR and append it to the end of the
11684  *   last bb instead of doing it in the epilog.
11685  * - change the store opcodes so they use sreg1 instead of dreg to store the base register.
11686  */
11687
11688 /*
11689
11690 NOTES
11691 -----
11692
11693 - When to decompose opcodes:
11694   - earlier: this makes some optimizations hard to implement, since the low level IR
11695   no longer contains the neccessary information. But it is easier to do.
11696   - later: harder to implement, enables more optimizations.
11697 - Branches inside bblocks:
11698   - created when decomposing complex opcodes. 
11699     - branches to another bblock: harmless, but not tracked by the branch 
11700       optimizations, so need to branch to a label at the start of the bblock.
11701     - branches to inside the same bblock: very problematic, trips up the local
11702       reg allocator. Can be fixed by spitting the current bblock, but that is a
11703       complex operation, since some local vregs can become global vregs etc.
11704 - Local/global vregs:
11705   - local vregs: temporary vregs used inside one bblock. Assigned to hregs by the
11706     local register allocator.
11707   - global vregs: used in more than one bblock. Have an associated MonoMethodVar
11708     structure, created by mono_create_var (). Assigned to hregs or the stack by
11709     the global register allocator.
11710 - When to do optimizations like alu->alu_imm:
11711   - earlier -> saves work later on since the IR will be smaller/simpler
11712   - later -> can work on more instructions
11713 - Handling of valuetypes:
11714   - When a vtype is pushed on the stack, a new temporary is created, an 
11715     instruction computing its address (LDADDR) is emitted and pushed on
11716     the stack. Need to optimize cases when the vtype is used immediately as in
11717     argument passing, stloc etc.
11718 - Instead of the to_end stuff in the old JIT, simply call the function handling
11719   the values on the stack before emitting the last instruction of the bb.
11720 */
11721
11722 #endif /* DISABLE_JIT */