2010-02-02 Zoltan Varga <vargaz@gmail.com>
[mono.git] / mono / mini / mini-arm.c
1 /*
2  * mini-arm.c: ARM backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2003 Ximian, Inc.
9  */
10 #include "mini.h"
11 #include <string.h>
12
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
15 #include <mono/utils/mono-mmap.h>
16
17 #include "mini-arm.h"
18 #include "cpu-arm.h"
19 #include "trace.h"
20 #include "ir-emit.h"
21 #ifdef ARM_FPU_FPA
22 #include "mono/arch/arm/arm-fpa-codegen.h"
23 #elif defined(ARM_FPU_VFP)
24 #include "mono/arch/arm/arm-vfp-codegen.h"
25 #endif
26
27 #if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID)
28 #define HAVE_AEABI_READ_TP 1
29 #endif
30
31 static gint lmf_tls_offset = -1;
32 static gint lmf_addr_tls_offset = -1;
33
34 /* This mutex protects architecture specific caches */
35 #define mono_mini_arch_lock() EnterCriticalSection (&mini_arch_mutex)
36 #define mono_mini_arch_unlock() LeaveCriticalSection (&mini_arch_mutex)
37 static CRITICAL_SECTION mini_arch_mutex;
38
39 static int v5_supported = 0;
40 static int v7_supported = 0;
41 static int thumb_supported = 0;
42
43 /*
44  * The code generated for sequence points reads from this location, which is
45  * made read-only when single stepping is enabled.
46  */
47 static gpointer ss_trigger_page;
48
49 /* Enabled breakpoints read from this trigger page */
50 static gpointer bp_trigger_page;
51
52 /* Structure used by the sequence points in AOTed code */
53 typedef struct {
54         gpointer ss_trigger_page;
55         gpointer bp_trigger_page;
56         guint8* bp_addrs [MONO_ZERO_LEN_ARRAY];
57 } SeqPointInfo;
58
59 /*
60  * TODO:
61  * floating point support: on ARM it is a mess, there are at least 3
62  * different setups, each of which binary incompat with the other.
63  * 1) FPA: old and ugly, but unfortunately what current distros use
64  *    the double binary format has the two words swapped. 8 double registers.
65  *    Implemented usually by kernel emulation.
66  * 2) softfloat: the compiler emulates all the fp ops. Usually uses the
67  *    ugly swapped double format (I guess a softfloat-vfp exists, too, though).
68  * 3) VFP: the new and actually sensible and useful FP support. Implemented
69  *    in HW or kernel-emulated, requires new tools. I think this is what symbian uses.
70  *
71  * The plan is to write the FPA support first. softfloat can be tested in a chroot.
72  */
73 int mono_exc_esp_offset = 0;
74
75 #define arm_is_imm12(v) ((v) > -4096 && (v) < 4096)
76 #define arm_is_imm8(v) ((v) > -256 && (v) < 256)
77 #define arm_is_fpimm8(v) ((v) >= -1020 && (v) <= 1020)
78
79 #define LDR_MASK ((0xf << ARMCOND_SHIFT) | (3 << 26) | (1 << 22) | (1 << 20) | (15 << 12))
80 #define LDR_PC_VAL ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 26) | (0 << 22) | (1 << 20) | (15 << 12))
81 #define IS_LDR_PC(val) (((val) & LDR_MASK) == LDR_PC_VAL)
82
83 #define ADD_LR_PC_4 ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 25) | (1 << 23) | (ARMREG_PC << 16) | (ARMREG_LR << 12) | 4)
84 #define MOV_LR_PC ((ARMCOND_AL << ARMCOND_SHIFT) | (1 << 24) | (0xa << 20) |  (ARMREG_LR << 12) | ARMREG_PC)
85 #define DEBUG_IMT 0
86  
87 /* A variant of ARM_LDR_IMM which can handle large offsets */
88 #define ARM_LDR_IMM_GENERAL(code, dreg, basereg, offset, scratch_reg) do { \
89         if (arm_is_imm12 ((offset))) { \
90                 ARM_LDR_IMM (code, (dreg), (basereg), (offset));        \
91         } else {                                                                                                \
92                 g_assert ((scratch_reg) != (basereg));                                     \
93                 code = mono_arm_emit_load_imm (code, (scratch_reg), (offset));  \
94                 ARM_LDR_REG_REG (code, (dreg), (basereg), (scratch_reg));               \
95         }                                                                                                                                       \
96         } while (0)
97
98 #define ARM_STR_IMM_GENERAL(code, dreg, basereg, offset, scratch_reg) do {      \
99         if (arm_is_imm12 ((offset))) { \
100                 ARM_STR_IMM (code, (dreg), (basereg), (offset));        \
101         } else {                                                                                                \
102                 g_assert ((scratch_reg) != (basereg));                                     \
103                 code = mono_arm_emit_load_imm (code, (scratch_reg), (offset));  \
104                 ARM_STR_REG_REG (code, (dreg), (basereg), (scratch_reg));               \
105         }                                                                                                                                       \
106         } while (0)
107
108 const char*
109 mono_arch_regname (int reg)
110 {
111         static const char * rnames[] = {
112                 "arm_r0", "arm_r1", "arm_r2", "arm_r3", "arm_v1",
113                 "arm_v2", "arm_v3", "arm_v4", "arm_v5", "arm_v6",
114                 "arm_v7", "arm_fp", "arm_ip", "arm_sp", "arm_lr",
115                 "arm_pc"
116         };
117         if (reg >= 0 && reg < 16)
118                 return rnames [reg];
119         return "unknown";
120 }
121
122 const char*
123 mono_arch_fregname (int reg)
124 {
125         static const char * rnames[] = {
126                 "arm_f0", "arm_f1", "arm_f2", "arm_f3", "arm_f4",
127                 "arm_f5", "arm_f6", "arm_f7", "arm_f8", "arm_f9",
128                 "arm_f10", "arm_f11", "arm_f12", "arm_f13", "arm_f14",
129                 "arm_f15", "arm_f16", "arm_f17", "arm_f18", "arm_f19",
130                 "arm_f20", "arm_f21", "arm_f22", "arm_f23", "arm_f24",
131                 "arm_f25", "arm_f26", "arm_f27", "arm_f28", "arm_f29",
132                 "arm_f30", "arm_f31"
133         };
134         if (reg >= 0 && reg < 32)
135                 return rnames [reg];
136         return "unknown";
137 }
138
139 static guint8*
140 emit_big_add (guint8 *code, int dreg, int sreg, int imm)
141 {
142         int imm8, rot_amount;
143         if ((imm8 = mono_arm_is_rotated_imm8 (imm, &rot_amount)) >= 0) {
144                 ARM_ADD_REG_IMM (code, dreg, sreg, imm8, rot_amount);
145                 return code;
146         }
147         g_assert (dreg != sreg);
148         code = mono_arm_emit_load_imm (code, dreg, imm);
149         ARM_ADD_REG_REG (code, dreg, dreg, sreg);
150         return code;
151 }
152
153 static guint8*
154 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
155 {
156         /* we can use r0-r3, since this is called only for incoming args on the stack */
157         if (size > sizeof (gpointer) * 4) {
158                 guint8 *start_loop;
159                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
160                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
161                 start_loop = code = mono_arm_emit_load_imm (code, ARMREG_R2, size);
162                 ARM_LDR_IMM (code, ARMREG_R3, ARMREG_R0, 0);
163                 ARM_STR_IMM (code, ARMREG_R3, ARMREG_R1, 0);
164                 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, 4);
165                 ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
166                 ARM_SUBS_REG_IMM8 (code, ARMREG_R2, ARMREG_R2, 4);
167                 ARM_B_COND (code, ARMCOND_NE, 0);
168                 arm_patch (code - 4, start_loop);
169                 return code;
170         }
171         if (arm_is_imm12 (doffset) && arm_is_imm12 (doffset + size) &&
172                         arm_is_imm12 (soffset) && arm_is_imm12 (soffset + size)) {
173                 while (size >= 4) {
174                         ARM_LDR_IMM (code, ARMREG_LR, sreg, soffset);
175                         ARM_STR_IMM (code, ARMREG_LR, dreg, doffset);
176                         doffset += 4;
177                         soffset += 4;
178                         size -= 4;
179                 }
180         } else if (size) {
181                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
182                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
183                 doffset = soffset = 0;
184                 while (size >= 4) {
185                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R0, soffset);
186                         ARM_STR_IMM (code, ARMREG_LR, ARMREG_R1, doffset);
187                         doffset += 4;
188                         soffset += 4;
189                         size -= 4;
190                 }
191         }
192         g_assert (size == 0);
193         return code;
194 }
195
196 static guint8*
197 emit_call_reg (guint8 *code, int reg)
198 {
199         if (v5_supported) {
200                 ARM_BLX_REG (code, reg);
201         } else {
202                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
203                 if (thumb_supported)
204                         ARM_BX (code, reg);
205                 else
206                         ARM_MOV_REG_REG (code, ARMREG_PC, reg);
207         }
208         return code;
209 }
210
211 static guint8*
212 emit_call_seq (MonoCompile *cfg, guint8 *code)
213 {
214         if (cfg->method->dynamic) {
215                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
216                 ARM_B (code, 0);
217                 *(gpointer*)code = NULL;
218                 code += 4;
219                 code = emit_call_reg (code, ARMREG_IP);
220         } else {
221                 ARM_BL (code, 0);
222         }
223         return code;
224 }
225
226 static guint8*
227 emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
228 {
229         switch (ins->opcode) {
230         case OP_FCALL:
231         case OP_FCALL_REG:
232         case OP_FCALL_MEMBASE:
233 #ifdef ARM_FPU_FPA
234                 if (ins->dreg != ARM_FPA_F0)
235                         ARM_MVFD (code, ins->dreg, ARM_FPA_F0);
236 #elif defined(ARM_FPU_VFP)
237                 if (((MonoCallInst*)ins)->signature->ret->type == MONO_TYPE_R4) {
238                         ARM_FMSR (code, ins->dreg, ARMREG_R0);
239                         ARM_CVTS (code, ins->dreg, ins->dreg);
240                 } else {
241                         ARM_FMDRR (code, ARMREG_R0, ARMREG_R1, ins->dreg);
242                 }
243 #endif
244                 break;
245         }
246
247         return code;
248 }
249
250 /*
251  * mono_arch_get_argument_info:
252  * @csig:  a method signature
253  * @param_count: the number of parameters to consider
254  * @arg_info: an array to store the result infos
255  *
256  * Gathers information on parameters such as size, alignment and
257  * padding. arg_info should be large enought to hold param_count + 1 entries. 
258  *
259  * Returns the size of the activation frame.
260  */
261 int
262 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
263 {
264         int k, frame_size = 0;
265         guint32 size, align, pad;
266         int offset = 8;
267
268         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
269                 frame_size += sizeof (gpointer);
270                 offset += 4;
271         }
272
273         arg_info [0].offset = offset;
274
275         if (csig->hasthis) {
276                 frame_size += sizeof (gpointer);
277                 offset += 4;
278         }
279
280         arg_info [0].size = frame_size;
281
282         for (k = 0; k < param_count; k++) {
283                 size = mini_type_stack_size_full (NULL, csig->params [k], &align, csig->pinvoke);
284
285                 /* ignore alignment for now */
286                 align = 1;
287
288                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
289                 arg_info [k].pad = pad;
290                 frame_size += size;
291                 arg_info [k + 1].pad = 0;
292                 arg_info [k + 1].size = size;
293                 offset += pad;
294                 arg_info [k + 1].offset = offset;
295                 offset += size;
296         }
297
298         align = MONO_ARCH_FRAME_ALIGNMENT;
299         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
300         arg_info [k].pad = pad;
301
302         return frame_size;
303 }
304
305 static gpointer
306 decode_vcall_slot_from_ldr (guint32 ldr, mgreg_t *regs, int *displacement)
307 {
308         char *o = NULL;
309         int reg, offset = 0;
310         reg = (ldr >> 16 ) & 0xf;
311         offset = ldr & 0xfff;
312         if (((ldr >> 23) & 1) == 0) /*U bit, 0 means negative and 1 positive*/
313                 offset = -offset;
314         /*g_print ("found vcall at r%d + %d for code at %p 0x%x\n", reg, offset, code, *code);*/
315         o = (gpointer)regs [reg];
316
317         *displacement = offset;
318         return o;
319 }
320
321 gpointer
322 mono_arch_get_vcall_slot (guint8 *code_ptr, mgreg_t *regs, int *displacement)
323 {
324         guint32* code = (guint32*)code_ptr;
325
326         /* Locate the address of the method-specific trampoline. The call using
327         the vtable slot that took the processing flow to 'arch_create_jit_trampoline' 
328         looks something like this:
329
330                 ldr rA, rX, #offset
331                 mov lr, pc
332                 mov pc, rA
333         or better:
334                 mov lr, pc
335                 ldr pc, rX, #offset
336
337         The call sequence could be also:
338                 ldr ip, pc, 0
339                 b skip
340                 function pointer literal
341                 skip:
342                 mov lr, pc
343                 mov pc, ip
344         Note that on ARM5+ we can use one instruction instead of the last two.
345         Therefore, we need to locate the 'ldr rA' instruction to know which
346         register was used to hold the method addrs.
347         */
348
349         /* This is the instruction after "ldc pc, xxx", "mov pc, xxx" or "bl xxx" could be either the IMT value or some other instruction*/
350         --code;
351
352         /* Three possible code sequences can happen here:
353          * interface call:
354          * 
355          * add lr, [pc + #4]
356          * ldr pc, [rX - #offset]
357          * .word IMT value
358          * 
359          * virtual call:
360          * 
361          * mov lr, pc
362          * ldr pc, [rX - #offset] 
363          * 
364          * direct branch with bl:
365          * 
366          * bl #offset
367          * 
368          * direct branch with mov: 
369          * 
370          * mv pc, rX
371          * 
372          * We only need to identify interface and virtual calls, the others can be ignored.
373          * 
374          */
375         if (IS_LDR_PC (code [-1]) && code [-2] == ADD_LR_PC_4)
376                 return decode_vcall_slot_from_ldr (code [-1], regs, displacement);
377
378         if (IS_LDR_PC (code [0]) && code [-1] == MOV_LR_PC)
379                 return decode_vcall_slot_from_ldr (code [0], regs, displacement);
380
381         return NULL;
382 }
383
384 #define MAX_ARCH_DELEGATE_PARAMS 3
385
386 static gpointer
387 get_delegate_invoke_impl (gboolean has_target, gboolean param_count, guint32 *code_size)
388 {
389         guint8 *code, *start;
390
391         if (has_target) {
392                 start = code = mono_global_codeman_reserve (12);
393
394                 /* Replace the this argument with the target */
395                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
396                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, target));
397                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
398
399                 g_assert ((code - start) <= 12);
400
401                 mono_arch_flush_icache (start, 12);
402         } else {
403                 int size, i;
404
405                 size = 8 + param_count * 4;
406                 start = code = mono_global_codeman_reserve (size);
407
408                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R0, G_STRUCT_OFFSET (MonoDelegate, method_ptr));
409                 /* slide down the arguments */
410                 for (i = 0; i < param_count; ++i) {
411                         ARM_MOV_REG_REG (code, (ARMREG_R0 + i), (ARMREG_R0 + i + 1));
412                 }
413                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
414
415                 g_assert ((code - start) <= size);
416
417                 mono_arch_flush_icache (start, size);
418         }
419
420         if (code_size)
421                 *code_size = code - start;
422
423         return start;
424 }
425
426 /*
427  * mono_arch_get_delegate_invoke_impls:
428  *
429  *   Return a list of MonoAotTrampInfo structures for the delegate invoke impl
430  * trampolines.
431  */
432 GSList*
433 mono_arch_get_delegate_invoke_impls (void)
434 {
435         GSList *res = NULL;
436         guint8 *code;
437         guint32 code_len;
438         int i;
439
440         code = get_delegate_invoke_impl (TRUE, 0, &code_len);
441         res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup ("delegate_invoke_impl_has_target"), code, code_len));
442
443         for (i = 0; i <= MAX_ARCH_DELEGATE_PARAMS; ++i) {
444                 code = get_delegate_invoke_impl (FALSE, i, &code_len);
445                 res = g_slist_prepend (res, mono_aot_tramp_info_create (g_strdup_printf ("delegate_invoke_impl_target_%d", i), code, code_len));
446         }
447
448         return res;
449 }
450
451 gpointer
452 mono_arch_get_delegate_invoke_impl (MonoMethodSignature *sig, gboolean has_target)
453 {
454         guint8 *code, *start;
455
456         /* FIXME: Support more cases */
457         if (MONO_TYPE_ISSTRUCT (sig->ret))
458                 return NULL;
459
460         if (has_target) {
461                 static guint8* cached = NULL;
462                 mono_mini_arch_lock ();
463                 if (cached) {
464                         mono_mini_arch_unlock ();
465                         return cached;
466                 }
467
468                 if (mono_aot_only)
469                         start = mono_aot_get_named_code ("delegate_invoke_impl_has_target");
470                 else
471                         start = get_delegate_invoke_impl (TRUE, 0, NULL);
472                 cached = start;
473                 mono_mini_arch_unlock ();
474                 return cached;
475         } else {
476                 static guint8* cache [MAX_ARCH_DELEGATE_PARAMS + 1] = {NULL};
477                 int i;
478
479                 if (sig->param_count > MAX_ARCH_DELEGATE_PARAMS)
480                         return NULL;
481                 for (i = 0; i < sig->param_count; ++i)
482                         if (!mono_is_regsize_var (sig->params [i]))
483                                 return NULL;
484
485                 mono_mini_arch_lock ();
486                 code = cache [sig->param_count];
487                 if (code) {
488                         mono_mini_arch_unlock ();
489                         return code;
490                 }
491
492                 if (mono_aot_only) {
493                         char *name = g_strdup_printf ("delegate_invoke_impl_target_%d", sig->param_count);
494                         start = mono_aot_get_named_code (name);
495                         g_free (name);
496                 } else {
497                         start = get_delegate_invoke_impl (FALSE, sig->param_count, NULL);
498                 }
499                 cache [sig->param_count] = start;
500                 mono_mini_arch_unlock ();
501                 return start;
502         }
503
504         return NULL;
505 }
506
507 gpointer
508 mono_arch_get_this_arg_from_call (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, mgreg_t *regs, guint8 *code)
509 {
510         /* FIXME: handle returning a struct */
511         if (MONO_TYPE_ISSTRUCT (sig->ret))
512                 return (gpointer)regs [ARMREG_R1];
513         return (gpointer)regs [ARMREG_R0];
514 }
515
516 /*
517  * Initialize the cpu to execute managed code.
518  */
519 void
520 mono_arch_cpu_init (void)
521 {
522 }
523
524 /*
525  * Initialize architecture specific code.
526  */
527 void
528 mono_arch_init (void)
529 {
530         InitializeCriticalSection (&mini_arch_mutex);
531
532         ss_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
533         bp_trigger_page = mono_valloc (NULL, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_32BIT);
534         mono_mprotect (bp_trigger_page, mono_pagesize (), 0);
535 }
536
537 /*
538  * Cleanup architecture specific code.
539  */
540 void
541 mono_arch_cleanup (void)
542 {
543 }
544
545 /*
546  * This function returns the optimizations supported on this cpu.
547  */
548 guint32
549 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
550 {
551         guint32 opts = 0;
552 #if __APPLE__
553         thumb_supported = TRUE;
554         v5_supported = TRUE;
555 #else
556         char buf [512];
557         char *line;
558         FILE *file = fopen ("/proc/cpuinfo", "r");
559         if (file) {
560                 while ((line = fgets (buf, 512, file))) {
561                         if (strncmp (line, "Processor", 9) == 0) {
562                                 char *ver = strstr (line, "(v");
563                                 if (ver && (ver [2] == '5' || ver [2] == '6' || ver [2] == '7'))
564                                         v5_supported = TRUE;
565                                 if (ver && (ver [2] == '7'))
566                                         v7_supported = TRUE;
567                                 continue;
568                         }
569                         if (strncmp (line, "Features", 8) == 0) {
570                                 char *th = strstr (line, "thumb");
571                                 if (th) {
572                                         thumb_supported = TRUE;
573                                         if (v5_supported)
574                                                 break;
575                                 }
576                                 continue;
577                         }
578                 }
579                 fclose (file);
580                 /*printf ("features: v5: %d, thumb: %d\n", v5_supported, thumb_supported);*/
581         }
582 #endif
583
584         /* no arm-specific optimizations yet */
585         *exclude_mask = 0;
586         return opts;
587 }
588
589 static gboolean
590 is_regsize_var (MonoType *t) {
591         if (t->byref)
592                 return TRUE;
593         t = mini_type_get_underlying_type (NULL, t);
594         switch (t->type) {
595         case MONO_TYPE_I4:
596         case MONO_TYPE_U4:
597         case MONO_TYPE_I:
598         case MONO_TYPE_U:
599         case MONO_TYPE_PTR:
600         case MONO_TYPE_FNPTR:
601                 return TRUE;
602         case MONO_TYPE_OBJECT:
603         case MONO_TYPE_STRING:
604         case MONO_TYPE_CLASS:
605         case MONO_TYPE_SZARRAY:
606         case MONO_TYPE_ARRAY:
607                 return TRUE;
608         case MONO_TYPE_GENERICINST:
609                 if (!mono_type_generic_inst_is_valuetype (t))
610                         return TRUE;
611                 return FALSE;
612         case MONO_TYPE_VALUETYPE:
613                 return FALSE;
614         }
615         return FALSE;
616 }
617
618 GList *
619 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
620 {
621         GList *vars = NULL;
622         int i;
623
624         for (i = 0; i < cfg->num_varinfo; i++) {
625                 MonoInst *ins = cfg->varinfo [i];
626                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
627
628                 /* unused vars */
629                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
630                         continue;
631
632                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
633                         continue;
634
635                 /* we can only allocate 32 bit values */
636                 if (is_regsize_var (ins->inst_vtype)) {
637                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
638                         g_assert (i == vmv->idx);
639                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
640                 }
641         }
642
643         return vars;
644 }
645
646 #define USE_EXTRA_TEMPS 0
647
648 GList *
649 mono_arch_get_global_int_regs (MonoCompile *cfg)
650 {
651         GList *regs = NULL;
652
653         /* 
654          * FIXME: Interface calls might go through a static rgctx trampoline which
655          * sets V5, but it doesn't save it, so we need to save it ourselves, and
656          * avoid using it.
657          */
658         if (cfg->flags & MONO_CFG_HAS_CALLS)
659                 cfg->uses_rgctx_reg = TRUE;
660
661         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V1));
662         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V2));
663         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V3));
664         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V4));
665         if (!(cfg->compile_aot || cfg->uses_rgctx_reg))
666                 /* V5 is reserved for passing the vtable/rgctx/IMT method */
667                 regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
668         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V6));*/
669         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));*/
670
671         return regs;
672 }
673
674 /*
675  * mono_arch_regalloc_cost:
676  *
677  *  Return the cost, in number of memory references, of the action of 
678  * allocating the variable VMV into a register during global register
679  * allocation.
680  */
681 guint32
682 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
683 {
684         /* FIXME: */
685         return 2;
686 }
687
688 #ifndef __GNUC_PREREQ
689 #define __GNUC_PREREQ(maj, min) (0)
690 #endif
691
692 void
693 mono_arch_flush_icache (guint8 *code, gint size)
694 {
695 #if __APPLE__
696         sys_icache_invalidate (code, size);
697 #elif __GNUC_PREREQ(4, 1)
698         __clear_cache (code, code + size);
699 #elif defined(PLATFORM_ANDROID)
700         const int syscall = 0xf0002;
701         __asm __volatile (
702                 "mov     r0, %0\n"                      
703                 "mov     r1, %1\n"
704                 "mov     r7, %2\n"
705                 "mov     r2, #0x0\n"
706                 "svc     0x00000000\n"
707                 :
708                 :       "r" (code), "r" (code + size), "r" (syscall)
709                 :       "r0", "r1", "r7", "r2"
710                 );
711 #else
712         __asm __volatile ("mov r0, %0\n"
713                         "mov r1, %1\n"
714                         "mov r2, %2\n"
715                         "swi 0x9f0002       @ sys_cacheflush"
716                         : /* no outputs */
717                         : "r" (code), "r" (code + size), "r" (0)
718                         : "r0", "r1", "r3" );
719 #endif
720 }
721
722 typedef enum {
723         RegTypeNone,
724         RegTypeGeneral,
725         RegTypeIRegPair,
726         RegTypeBase,
727         RegTypeBaseGen,
728         RegTypeFP,
729         RegTypeStructByVal,
730         RegTypeStructByAddr
731 } ArgStorage;
732
733 typedef struct {
734         gint32  offset;
735         guint16 vtsize; /* in param area */
736         guint8  reg;
737         ArgStorage  storage;
738         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
739 } ArgInfo;
740
741 typedef struct {
742         int nargs;
743         guint32 stack_usage;
744         guint32 struct_ret;
745         gboolean vtype_retaddr;
746         ArgInfo ret;
747         ArgInfo sig_cookie;
748         ArgInfo args [1];
749 } CallInfo;
750
751 #define DEBUG(a)
752
753 #ifndef __GNUC__
754 /*#define __alignof__(a) sizeof(a)*/
755 #define __alignof__(type) G_STRUCT_OFFSET(struct { char c; type x; }, x)
756 #endif
757
758 #define PARAM_REGS 4
759
760 static void inline
761 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
762 {
763         if (simple) {
764                 if (*gr > ARMREG_R3) {
765                         ainfo->offset = *stack_size;
766                         ainfo->reg = ARMREG_SP; /* in the caller */
767                         ainfo->storage = RegTypeBase;
768                         *stack_size += 4;
769                 } else {
770                         ainfo->storage = RegTypeGeneral;
771                         ainfo->reg = *gr;
772                 }
773         } else {
774 #if defined(__APPLE__) && defined(MONO_CROSS_COMPILE)
775                 int i8_align = 4;
776 #else
777                 int i8_align = __alignof__ (gint64);
778 #endif
779
780 #if __ARM_EABI__
781                 gboolean split = i8_align == 4;
782 #else
783                 gboolean split = TRUE;
784 #endif
785                 
786                 if (*gr == ARMREG_R3 && split) {
787                         /* first word in r3 and the second on the stack */
788                         ainfo->offset = *stack_size;
789                         ainfo->reg = ARMREG_SP; /* in the caller */
790                         ainfo->storage = RegTypeBaseGen;
791                         *stack_size += 4;
792                 } else if (*gr >= ARMREG_R3) {
793 #ifdef __ARM_EABI__
794                         /* darwin aligns longs to 4 byte only */
795                         if (i8_align == 8) {
796                                 *stack_size += 7;
797                                 *stack_size &= ~7;
798                         }
799 #endif
800                         ainfo->offset = *stack_size;
801                         ainfo->reg = ARMREG_SP; /* in the caller */
802                         ainfo->storage = RegTypeBase;
803                         *stack_size += 8;
804                 } else {
805 #ifdef __ARM_EABI__
806                         if (i8_align == 8 && ((*gr) & 1))
807                                 (*gr) ++;
808 #endif
809                         ainfo->storage = RegTypeIRegPair;
810                         ainfo->reg = *gr;
811                 }
812                 (*gr) ++;
813         }
814         (*gr) ++;
815 }
816
817 static CallInfo*
818 get_call_info (MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
819 {
820         guint i, gr;
821         int n = sig->hasthis + sig->param_count;
822         MonoType *simpletype;
823         guint32 stack_size = 0;
824         CallInfo *cinfo;
825
826         if (mp)
827                 cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
828         else
829                 cinfo = g_malloc0 (sizeof (CallInfo) + (sizeof (ArgInfo) * n));
830
831         cinfo->nargs = n;
832         gr = ARMREG_R0;
833
834         /* FIXME: handle returning a struct */
835         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
836                 guint32 align;
837
838                 if (is_pinvoke && mono_class_native_size (mono_class_from_mono_type (sig->ret), &align) <= sizeof (gpointer)) {
839                         cinfo->ret.storage = RegTypeStructByVal;
840                 } else {
841                         add_general (&gr, &stack_size, &cinfo->ret, TRUE);
842                         cinfo->struct_ret = ARMREG_R0;
843                         cinfo->vtype_retaddr = TRUE;
844                 }
845         }
846
847         n = 0;
848         if (sig->hasthis) {
849                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
850                 n++;
851         }
852         DEBUG(printf("params: %d\n", sig->param_count));
853         for (i = 0; i < sig->param_count; ++i) {
854                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
855                         /* Prevent implicit arguments and sig_cookie from
856                            being passed in registers */
857                         gr = ARMREG_R3 + 1;
858                         /* Emit the signature cookie just before the implicit arguments */
859                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
860                 }
861                 DEBUG(printf("param %d: ", i));
862                 if (sig->params [i]->byref) {
863                         DEBUG(printf("byref\n"));
864                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
865                         n++;
866                         continue;
867                 }
868                 simpletype = mini_type_get_underlying_type (NULL, sig->params [i]);
869                 switch (simpletype->type) {
870                 case MONO_TYPE_BOOLEAN:
871                 case MONO_TYPE_I1:
872                 case MONO_TYPE_U1:
873                         cinfo->args [n].size = 1;
874                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
875                         n++;
876                         break;
877                 case MONO_TYPE_CHAR:
878                 case MONO_TYPE_I2:
879                 case MONO_TYPE_U2:
880                         cinfo->args [n].size = 2;
881                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
882                         n++;
883                         break;
884                 case MONO_TYPE_I4:
885                 case MONO_TYPE_U4:
886                         cinfo->args [n].size = 4;
887                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
888                         n++;
889                         break;
890                 case MONO_TYPE_I:
891                 case MONO_TYPE_U:
892                 case MONO_TYPE_PTR:
893                 case MONO_TYPE_FNPTR:
894                 case MONO_TYPE_CLASS:
895                 case MONO_TYPE_OBJECT:
896                 case MONO_TYPE_STRING:
897                 case MONO_TYPE_SZARRAY:
898                 case MONO_TYPE_ARRAY:
899                 case MONO_TYPE_R4:
900                         cinfo->args [n].size = sizeof (gpointer);
901                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
902                         n++;
903                         break;
904                 case MONO_TYPE_GENERICINST:
905                         if (!mono_type_generic_inst_is_valuetype (simpletype)) {
906                                 cinfo->args [n].size = sizeof (gpointer);
907                                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
908                                 n++;
909                                 break;
910                         }
911                         /* Fall through */
912                 case MONO_TYPE_TYPEDBYREF:
913                 case MONO_TYPE_VALUETYPE: {
914                         gint size;
915                         int align_size;
916                         int nwords;
917                         guint32 align;
918
919                         if (simpletype->type == MONO_TYPE_TYPEDBYREF) {
920                                 size = sizeof (MonoTypedRef);
921                                 align = sizeof (gpointer);
922                         } else {
923                                 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
924                                 if (is_pinvoke)
925                                         size = mono_class_native_size (klass, &align);
926                                 else
927                                         size = mono_class_value_size (klass, &align);
928                         }
929                         DEBUG(printf ("load %d bytes struct\n",
930                                       mono_class_native_size (sig->params [i]->data.klass, NULL)));
931                         align_size = size;
932                         nwords = 0;
933                         align_size += (sizeof (gpointer) - 1);
934                         align_size &= ~(sizeof (gpointer) - 1);
935                         nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
936                         cinfo->args [n].storage = RegTypeStructByVal;
937                         /* FIXME: align stack_size if needed */
938 #ifdef __ARM_EABI__
939                         if (align >= 8 && (gr & 1))
940                                 gr ++;
941 #endif
942                         if (gr > ARMREG_R3) {
943                                 cinfo->args [n].size = 0;
944                                 cinfo->args [n].vtsize = nwords;
945                         } else {
946                                 int rest = ARMREG_R3 - gr + 1;
947                                 int n_in_regs = rest >= nwords? nwords: rest;
948
949                                 cinfo->args [n].size = n_in_regs;
950                                 cinfo->args [n].vtsize = nwords - n_in_regs;
951                                 cinfo->args [n].reg = gr;
952                                 gr += n_in_regs;
953                                 nwords -= n_in_regs;
954                         }
955                         cinfo->args [n].offset = stack_size;
956                         /*g_print ("offset for arg %d at %d\n", n, stack_size);*/
957                         stack_size += nwords * sizeof (gpointer);
958                         n++;
959                         break;
960                 }
961                 case MONO_TYPE_U8:
962                 case MONO_TYPE_I8:
963                 case MONO_TYPE_R8:
964                         cinfo->args [n].size = 8;
965                         add_general (&gr, &stack_size, cinfo->args + n, FALSE);
966                         n++;
967                         break;
968                 default:
969                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
970                 }
971         }
972
973         /* Handle the case where there are no implicit arguments */
974         if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
975                 /* Prevent implicit arguments and sig_cookie from
976                    being passed in registers */
977                 gr = ARMREG_R3 + 1;
978                 /* Emit the signature cookie just before the implicit arguments */
979                 add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
980         }
981
982         {
983                 simpletype = mini_type_get_underlying_type (NULL, sig->ret);
984                 switch (simpletype->type) {
985                 case MONO_TYPE_BOOLEAN:
986                 case MONO_TYPE_I1:
987                 case MONO_TYPE_U1:
988                 case MONO_TYPE_I2:
989                 case MONO_TYPE_U2:
990                 case MONO_TYPE_CHAR:
991                 case MONO_TYPE_I4:
992                 case MONO_TYPE_U4:
993                 case MONO_TYPE_I:
994                 case MONO_TYPE_U:
995                 case MONO_TYPE_PTR:
996                 case MONO_TYPE_FNPTR:
997                 case MONO_TYPE_CLASS:
998                 case MONO_TYPE_OBJECT:
999                 case MONO_TYPE_SZARRAY:
1000                 case MONO_TYPE_ARRAY:
1001                 case MONO_TYPE_STRING:
1002                         cinfo->ret.storage = RegTypeGeneral;
1003                         cinfo->ret.reg = ARMREG_R0;
1004                         break;
1005                 case MONO_TYPE_U8:
1006                 case MONO_TYPE_I8:
1007                         cinfo->ret.storage = RegTypeIRegPair;
1008                         cinfo->ret.reg = ARMREG_R0;
1009                         break;
1010                 case MONO_TYPE_R4:
1011                 case MONO_TYPE_R8:
1012                         cinfo->ret.storage = RegTypeFP;
1013                         cinfo->ret.reg = ARMREG_R0;
1014                         /* FIXME: cinfo->ret.reg = ???;
1015                         cinfo->ret.storage = RegTypeFP;*/
1016                         break;
1017                 case MONO_TYPE_GENERICINST:
1018                         if (!mono_type_generic_inst_is_valuetype (simpletype)) {
1019                                 cinfo->ret.storage = RegTypeGeneral;
1020                                 cinfo->ret.reg = ARMREG_R0;
1021                                 break;
1022                         }
1023                         /* Fall through */
1024                 case MONO_TYPE_VALUETYPE:
1025                 case MONO_TYPE_TYPEDBYREF:
1026                         if (cinfo->ret.storage != RegTypeStructByVal)
1027                                 cinfo->ret.storage = RegTypeStructByAddr;
1028                         break;
1029                 case MONO_TYPE_VOID:
1030                         break;
1031                 default:
1032                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
1033                 }
1034         }
1035
1036         /* align stack size to 8 */
1037         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
1038         stack_size = (stack_size + 7) & ~7;
1039
1040         cinfo->stack_usage = stack_size;
1041         return cinfo;
1042 }
1043
1044
1045 /*
1046  * Set var information according to the calling convention. arm version.
1047  * The locals var stuff should most likely be split in another method.
1048  */
1049 void
1050 mono_arch_allocate_vars (MonoCompile *cfg)
1051 {
1052         MonoMethodSignature *sig;
1053         MonoMethodHeader *header;
1054         MonoInst *inst;
1055         int i, offset, size, align, curinst;
1056         int frame_reg = ARMREG_FP;
1057         CallInfo *cinfo;
1058         guint32 ualign;
1059
1060         sig = mono_method_signature (cfg->method);
1061
1062         if (!cfg->arch.cinfo)
1063                 cfg->arch.cinfo = get_call_info (cfg->mempool, sig, sig->pinvoke);
1064         cinfo = cfg->arch.cinfo;
1065
1066         /* FIXME: this will change when we use FP as gcc does */
1067         cfg->flags |= MONO_CFG_HAS_SPILLUP;
1068
1069         /* allow room for the vararg method args: void* and long/double */
1070         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1071                 cfg->param_area = MAX (cfg->param_area, sizeof (gpointer)*8);
1072
1073         header = mono_method_get_header (cfg->method);
1074
1075         /* 
1076          * We use the frame register also for any method that has
1077          * exception clauses. This way, when the handlers are called,
1078          * the code will reference local variables using the frame reg instead of
1079          * the stack pointer: if we had to restore the stack pointer, we'd
1080          * corrupt the method frames that are already on the stack (since
1081          * filters get called before stack unwinding happens) when the filter
1082          * code would call any method (this also applies to finally etc.).
1083          */ 
1084         if ((cfg->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
1085                 frame_reg = ARMREG_FP;
1086         cfg->frame_reg = frame_reg;
1087         if (frame_reg != ARMREG_SP) {
1088                 cfg->used_int_regs |= 1 << frame_reg;
1089         }
1090
1091         if (cfg->compile_aot || cfg->uses_rgctx_reg)
1092                 /* V5 is reserved for passing the vtable/rgctx/IMT method */
1093                 cfg->used_int_regs |= (1 << ARMREG_V5);
1094
1095         offset = 0;
1096         curinst = 0;
1097         if (!MONO_TYPE_ISSTRUCT (sig->ret)) {
1098                 switch (mini_type_get_underlying_type (NULL, sig->ret)->type) {
1099                 case MONO_TYPE_VOID:
1100                         break;
1101                 default:
1102                         cfg->ret->opcode = OP_REGVAR;
1103                         cfg->ret->inst_c0 = ARMREG_R0;
1104                         break;
1105                 }
1106         }
1107         /* local vars are at a positive offset from the stack pointer */
1108         /* 
1109          * also note that if the function uses alloca, we use FP
1110          * to point at the local variables.
1111          */
1112         offset = 0; /* linkage area */
1113         /* align the offset to 16 bytes: not sure this is needed here  */
1114         //offset += 8 - 1;
1115         //offset &= ~(8 - 1);
1116
1117         /* add parameter area size for called functions */
1118         offset += cfg->param_area;
1119         offset += 8 - 1;
1120         offset &= ~(8 - 1);
1121         if (cfg->flags & MONO_CFG_HAS_FPOUT)
1122                 offset += 8;
1123
1124         /* allow room to save the return value */
1125         if (mono_jit_trace_calls != NULL && mono_trace_eval (cfg->method))
1126                 offset += 8;
1127
1128         /* the MonoLMF structure is stored just below the stack pointer */
1129         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
1130                 if (cinfo->ret.storage == RegTypeStructByVal) {
1131                         cfg->ret->opcode = OP_REGOFFSET;
1132                         cfg->ret->inst_basereg = cfg->frame_reg;
1133                         offset += sizeof (gpointer) - 1;
1134                         offset &= ~(sizeof (gpointer) - 1);
1135                         cfg->ret->inst_offset = - offset;
1136                 } else {
1137                         inst = cfg->vret_addr;
1138                         offset += sizeof(gpointer) - 1;
1139                         offset &= ~(sizeof(gpointer) - 1);
1140                         inst->inst_offset = offset;
1141                         inst->opcode = OP_REGOFFSET;
1142                         inst->inst_basereg = frame_reg;
1143                         if (G_UNLIKELY (cfg->verbose_level > 1)) {
1144                                 printf ("vret_addr =");
1145                                 mono_print_ins (cfg->vret_addr);
1146                         }
1147                 }
1148                 offset += sizeof(gpointer);
1149         }
1150
1151         curinst = cfg->locals_start;
1152         for (i = curinst; i < cfg->num_varinfo; ++i) {
1153                 inst = cfg->varinfo [i];
1154                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
1155                         continue;
1156
1157                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
1158                 * pinvoke wrappers when they call functions returning structure */
1159                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF) {
1160                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &ualign);
1161                         align = ualign;
1162                 }
1163                 else
1164                         size = mono_type_size (inst->inst_vtype, &align);
1165
1166                 /* FIXME: if a structure is misaligned, our memcpy doesn't work,
1167                  * since it loads/stores misaligned words, which don't do the right thing.
1168                  */
1169                 if (align < 4 && size >= 4)
1170                         align = 4;
1171                 offset += align - 1;
1172                 offset &= ~(align - 1);
1173                 inst->inst_offset = offset;
1174                 inst->opcode = OP_REGOFFSET;
1175                 inst->inst_basereg = frame_reg;
1176                 offset += size;
1177                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
1178         }
1179
1180         curinst = 0;
1181         if (sig->hasthis) {
1182                 inst = cfg->args [curinst];
1183                 if (inst->opcode != OP_REGVAR) {
1184                         inst->opcode = OP_REGOFFSET;
1185                         inst->inst_basereg = frame_reg;
1186                         offset += sizeof (gpointer) - 1;
1187                         offset &= ~(sizeof (gpointer) - 1);
1188                         inst->inst_offset = offset;
1189                         offset += sizeof (gpointer);
1190                 }
1191                 curinst++;
1192         }
1193
1194         if (sig->call_convention == MONO_CALL_VARARG) {
1195                 size = 4;
1196                 align = 4;
1197
1198                 /* Allocate a local slot to hold the sig cookie address */
1199                 offset += align - 1;
1200                 offset &= ~(align - 1);
1201                 cfg->sig_cookie = offset;
1202                 offset += size;
1203         }                       
1204
1205         for (i = 0; i < sig->param_count; ++i) {
1206                 inst = cfg->args [curinst];
1207
1208                 if (inst->opcode != OP_REGVAR) {
1209                         inst->opcode = OP_REGOFFSET;
1210                         inst->inst_basereg = frame_reg;
1211                         size = mini_type_stack_size_full (NULL, sig->params [i], &ualign, sig->pinvoke);
1212                         align = ualign;
1213                         /* FIXME: if a structure is misaligned, our memcpy doesn't work,
1214                          * since it loads/stores misaligned words, which don't do the right thing.
1215                          */
1216                         if (align < 4 && size >= 4)
1217                                 align = 4;
1218                         /* The code in the prolog () stores words when storing vtypes received in a register */
1219                         if (MONO_TYPE_ISSTRUCT (sig->params [i]))
1220                                 align = 4;
1221                         offset += align - 1;
1222                         offset &= ~(align - 1);
1223                         inst->inst_offset = offset;
1224                         offset += size;
1225                 }
1226                 curinst++;
1227         }
1228
1229         /* align the offset to 8 bytes */
1230         offset += 8 - 1;
1231         offset &= ~(8 - 1);
1232
1233         /* change sign? */
1234         cfg->stack_offset = offset;
1235 }
1236
1237 void
1238 mono_arch_create_vars (MonoCompile *cfg)
1239 {
1240         MonoMethodSignature *sig;
1241         CallInfo *cinfo;
1242
1243         sig = mono_method_signature (cfg->method);
1244
1245         if (!cfg->arch.cinfo)
1246                 cfg->arch.cinfo = get_call_info (cfg->mempool, sig, sig->pinvoke);
1247         cinfo = cfg->arch.cinfo;
1248
1249         if (cinfo->ret.storage == RegTypeStructByVal)
1250                 cfg->ret_var_is_local = TRUE;
1251
1252         if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage != RegTypeStructByVal) {
1253                 cfg->vret_addr = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_ARG);
1254                 if (G_UNLIKELY (cfg->verbose_level > 1)) {
1255                         printf ("vret_addr = ");
1256                         mono_print_ins (cfg->vret_addr);
1257                 }
1258         }
1259
1260         if (cfg->gen_seq_points && cfg->compile_aot) {
1261             MonoInst *ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1262                 ins->flags |= MONO_INST_VOLATILE;
1263                 cfg->arch.seq_point_info_var = ins;
1264
1265                 /* Allocate a separate variable for this to save 1 load per seq point */
1266             ins = mono_compile_create_var (cfg, &mono_defaults.int_class->byval_arg, OP_LOCAL);
1267                 ins->flags |= MONO_INST_VOLATILE;
1268                 cfg->arch.ss_trigger_page_var = ins;
1269         }
1270 }
1271
1272 static void
1273 emit_sig_cookie (MonoCompile *cfg, MonoCallInst *call, CallInfo *cinfo)
1274 {
1275         MonoMethodSignature *tmp_sig;
1276         MonoInst *sig_arg;
1277
1278         if (call->tail_call)
1279                 NOT_IMPLEMENTED;
1280
1281         /* FIXME: Add support for signature tokens to AOT */
1282         cfg->disable_aot = TRUE;
1283
1284         g_assert (cinfo->sig_cookie.storage == RegTypeBase);
1285                         
1286         /*
1287          * mono_ArgIterator_Setup assumes the signature cookie is 
1288          * passed first and all the arguments which were before it are
1289          * passed on the stack after the signature. So compensate by 
1290          * passing a different signature.
1291          */
1292         tmp_sig = mono_metadata_signature_dup (call->signature);
1293         tmp_sig->param_count -= call->signature->sentinelpos;
1294         tmp_sig->sentinelpos = 0;
1295         memcpy (tmp_sig->params, call->signature->params + call->signature->sentinelpos, tmp_sig->param_count * sizeof (MonoType*));
1296
1297         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
1298         sig_arg->dreg = mono_alloc_ireg (cfg);
1299         sig_arg->inst_p0 = tmp_sig;
1300         MONO_ADD_INS (cfg->cbb, sig_arg);
1301
1302         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, cinfo->sig_cookie.offset, sig_arg->dreg);
1303 }
1304
1305 #ifdef ENABLE_LLVM
1306 LLVMCallInfo*
1307 mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
1308 {
1309         int i, n;
1310         CallInfo *cinfo;
1311         ArgInfo *ainfo;
1312         LLVMCallInfo *linfo;
1313
1314         n = sig->param_count + sig->hasthis;
1315
1316         cinfo = get_call_info (cfg->mempool, sig, sig->pinvoke);
1317
1318         linfo = mono_mempool_alloc0 (cfg->mempool, sizeof (LLVMCallInfo) + (sizeof (LLVMArgInfo) * n));
1319
1320         /*
1321          * LLVM always uses the native ABI while we use our own ABI, the
1322          * only difference is the handling of vtypes:
1323          * - we only pass/receive them in registers in some cases, and only 
1324          *   in 1 or 2 integer registers.
1325          */
1326         if (cinfo->ret.storage != RegTypeGeneral && cinfo->ret.storage != RegTypeNone && cinfo->ret.storage != RegTypeFP && cinfo->ret.storage != RegTypeIRegPair) {
1327                 cfg->exception_message = g_strdup ("unknown ret conv");
1328                 cfg->disable_llvm = TRUE;
1329                 return linfo;
1330         }
1331
1332         for (i = 0; i < n; ++i) {
1333                 ainfo = cinfo->args + i;
1334
1335                 linfo->args [i].storage = LLVMArgNone;
1336
1337                 switch (ainfo->storage) {
1338                 case RegTypeGeneral:
1339                 case RegTypeIRegPair:
1340                 case RegTypeBase:
1341                         linfo->args [i].storage = LLVMArgInIReg;
1342                         break;
1343                 default:
1344                         cfg->exception_message = g_strdup_printf ("ainfo->storage (%d)", ainfo->storage);
1345                         cfg->disable_llvm = TRUE;
1346                         break;
1347                 }
1348         }
1349
1350         return linfo;
1351 }
1352 #endif
1353
1354 void
1355 mono_arch_emit_call (MonoCompile *cfg, MonoCallInst *call)
1356 {
1357         MonoInst *in, *ins;
1358         MonoMethodSignature *sig;
1359         int i, n;
1360         CallInfo *cinfo;
1361
1362         sig = call->signature;
1363         n = sig->param_count + sig->hasthis;
1364         
1365         cinfo = get_call_info (NULL, sig, sig->pinvoke);
1366
1367         for (i = 0; i < n; ++i) {
1368                 ArgInfo *ainfo = cinfo->args + i;
1369                 MonoType *t;
1370
1371                 if (i >= sig->hasthis)
1372                         t = sig->params [i - sig->hasthis];
1373                 else
1374                         t = &mono_defaults.int_class->byval_arg;
1375                 t = mini_type_get_underlying_type (NULL, t);
1376
1377                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
1378                         /* Emit the signature cookie just before the implicit arguments */
1379                         emit_sig_cookie (cfg, call, cinfo);
1380                 }
1381
1382                 in = call->args [i];
1383
1384                 switch (ainfo->storage) {
1385                 case RegTypeGeneral:
1386                 case RegTypeIRegPair:
1387                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1388                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1389                                 ins->dreg = mono_alloc_ireg (cfg);
1390                                 ins->sreg1 = in->dreg + 1;
1391                                 MONO_ADD_INS (cfg->cbb, ins);
1392                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1393
1394                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1395                                 ins->dreg = mono_alloc_ireg (cfg);
1396                                 ins->sreg1 = in->dreg + 2;
1397                                 MONO_ADD_INS (cfg->cbb, ins);
1398                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1399                         } else if (!t->byref && ((t->type == MONO_TYPE_R8) || (t->type == MONO_TYPE_R4))) {
1400 #ifndef MONO_ARCH_SOFT_FLOAT
1401                                 int creg;
1402 #endif
1403
1404                                 if (ainfo->size == 4) {
1405 #ifdef MONO_ARCH_SOFT_FLOAT
1406                                         /* mono_emit_call_args () have already done the r8->r4 conversion */
1407                                         /* The converted value is in an int vreg */
1408                                         MONO_INST_NEW (cfg, ins, OP_MOVE);
1409                                         ins->dreg = mono_alloc_ireg (cfg);
1410                                         ins->sreg1 = in->dreg;
1411                                         MONO_ADD_INS (cfg->cbb, ins);
1412                                         mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1413 #else
1414                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
1415                                         creg = mono_alloc_ireg (cfg);
1416                                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
1417                                         mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg, FALSE);
1418 #endif
1419                                 } else {
1420 #ifdef MONO_ARCH_SOFT_FLOAT
1421                                         MONO_INST_NEW (cfg, ins, OP_FGETLOW32);
1422                                         ins->dreg = mono_alloc_ireg (cfg);
1423                                         ins->sreg1 = in->dreg;
1424                                         MONO_ADD_INS (cfg->cbb, ins);
1425                                         mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1426
1427                                         MONO_INST_NEW (cfg, ins, OP_FGETHIGH32);
1428                                         ins->dreg = mono_alloc_ireg (cfg);
1429                                         ins->sreg1 = in->dreg;
1430                                         MONO_ADD_INS (cfg->cbb, ins);
1431                                         mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg + 1, FALSE);
1432 #else
1433                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
1434                                         creg = mono_alloc_ireg (cfg);
1435                                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
1436                                         mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg, FALSE);
1437                                         creg = mono_alloc_ireg (cfg);
1438                                         MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8 + 4));
1439                                         mono_call_inst_add_outarg_reg (cfg, call, creg, ainfo->reg + 1, FALSE);
1440 #endif
1441                                 }
1442                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1443                         } else {
1444                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1445                                 ins->dreg = mono_alloc_ireg (cfg);
1446                                 ins->sreg1 = in->dreg;
1447                                 MONO_ADD_INS (cfg->cbb, ins);
1448
1449                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ainfo->reg, FALSE);
1450                         }
1451                         break;
1452                 case RegTypeStructByAddr:
1453                         NOT_IMPLEMENTED;
1454 #if 0
1455                         /* FIXME: where si the data allocated? */
1456                         arg->backend.reg3 = ainfo->reg;
1457                         call->used_iregs |= 1 << ainfo->reg;
1458                         g_assert_not_reached ();
1459 #endif
1460                         break;
1461                 case RegTypeStructByVal:
1462                         MONO_INST_NEW (cfg, ins, OP_OUTARG_VT);
1463                         ins->opcode = OP_OUTARG_VT;
1464                         ins->sreg1 = in->dreg;
1465                         ins->klass = in->klass;
1466                         ins->inst_p0 = call;
1467                         ins->inst_p1 = mono_mempool_alloc (cfg->mempool, sizeof (ArgInfo));
1468                         memcpy (ins->inst_p1, ainfo, sizeof (ArgInfo));
1469                         MONO_ADD_INS (cfg->cbb, ins);
1470                         break;
1471                 case RegTypeBase:
1472                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1473                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
1474                         } else if (!t->byref && ((t->type == MONO_TYPE_R4) || (t->type == MONO_TYPE_R8))) {
1475                                 if (t->type == MONO_TYPE_R8) {
1476                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
1477                                 } else {
1478 #ifdef MONO_ARCH_SOFT_FLOAT
1479                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI4_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
1480 #else
1481                                         MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
1482 #endif
1483                                 }
1484                         } else {
1485                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, in->dreg);
1486                         }
1487                         break;
1488                 case RegTypeBaseGen:
1489                         if (!t->byref && ((t->type == MONO_TYPE_I8) || (t->type == MONO_TYPE_U8))) {
1490                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, (G_BYTE_ORDER == G_BIG_ENDIAN) ? in->dreg + 1 : in->dreg + 2);
1491                                 MONO_INST_NEW (cfg, ins, OP_MOVE);
1492                                 ins->dreg = mono_alloc_ireg (cfg);
1493                                 ins->sreg1 = G_BYTE_ORDER == G_BIG_ENDIAN ? in->dreg + 2 : in->dreg + 1;
1494                                 MONO_ADD_INS (cfg->cbb, ins);
1495                                 mono_call_inst_add_outarg_reg (cfg, call, ins->dreg, ARMREG_R3, FALSE);
1496                         } else if (!t->byref && (t->type == MONO_TYPE_R8)) {
1497                                 int creg;
1498
1499 #ifdef MONO_ARCH_SOFT_FLOAT
1500                                 g_assert_not_reached ();
1501 #endif
1502
1503                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
1504                                 creg = mono_alloc_ireg (cfg);
1505                                 mono_call_inst_add_outarg_reg (cfg, call, creg, ARMREG_R3, FALSE);
1506                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
1507                                 creg = mono_alloc_ireg (cfg);
1508                                 MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 4));
1509                                 MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, ARMREG_SP, ainfo->offset, creg);
1510                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
1511                         } else {
1512                                 g_assert_not_reached ();
1513                         }
1514                         break;
1515                 case RegTypeFP: {
1516                         /* FIXME: */
1517                         NOT_IMPLEMENTED;
1518 #if 0
1519                         arg->backend.reg3 = ainfo->reg;
1520                         /* FP args are passed in int regs */
1521                         call->used_iregs |= 1 << ainfo->reg;
1522                         if (ainfo->size == 8) {
1523                                 arg->opcode = OP_OUTARG_R8;
1524                                 call->used_iregs |= 1 << (ainfo->reg + 1);
1525                         } else {
1526                                 arg->opcode = OP_OUTARG_R4;
1527                         }
1528 #endif
1529                         cfg->flags |= MONO_CFG_HAS_FPOUT;
1530                         break;
1531                 }
1532                 default:
1533                         g_assert_not_reached ();
1534                 }
1535         }
1536
1537         /* Handle the case where there are no implicit arguments */
1538         if (!sig->pinvoke && (sig->call_convention == MONO_CALL_VARARG) && (n == sig->sentinelpos))
1539                 emit_sig_cookie (cfg, call, cinfo);
1540
1541         if (sig->ret && MONO_TYPE_ISSTRUCT (sig->ret)) {
1542                 MonoInst *vtarg;
1543
1544                 if (cinfo->ret.storage == RegTypeStructByVal) {
1545                         /* The JIT will transform this into a normal call */
1546                         call->vret_in_reg = TRUE;
1547                 } else {
1548                         MONO_INST_NEW (cfg, vtarg, OP_MOVE);
1549                         vtarg->sreg1 = call->vret_var->dreg;
1550                         vtarg->dreg = mono_alloc_preg (cfg);
1551                         MONO_ADD_INS (cfg->cbb, vtarg);
1552
1553                         mono_call_inst_add_outarg_reg (cfg, call, vtarg->dreg, cinfo->ret.reg, FALSE);
1554                 }
1555         }
1556
1557         call->stack_usage = cinfo->stack_usage;
1558
1559         g_free (cinfo);
1560 }
1561
1562 void
1563 mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src)
1564 {
1565         MonoCallInst *call = (MonoCallInst*)ins->inst_p0;
1566         ArgInfo *ainfo = ins->inst_p1;
1567         int ovf_size = ainfo->vtsize;
1568         int doffset = ainfo->offset;
1569         int i, soffset, dreg;
1570
1571         soffset = 0;
1572         for (i = 0; i < ainfo->size; ++i) {
1573                 dreg = mono_alloc_ireg (cfg);
1574                 MONO_EMIT_NEW_LOAD_MEMBASE (cfg, dreg, src->dreg, soffset);
1575                 mono_call_inst_add_outarg_reg (cfg, call, dreg, ainfo->reg + i, FALSE);
1576                 soffset += sizeof (gpointer);
1577         }
1578         //g_print ("vt size: %d at R%d + %d\n", doffset, vt->inst_basereg, vt->inst_offset);
1579         if (ovf_size != 0)
1580                 mini_emit_memcpy (cfg, ARMREG_SP, doffset, src->dreg, soffset, ovf_size * sizeof (gpointer), 0);
1581 }
1582
1583 void
1584 mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val)
1585 {
1586         MonoType *ret = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret);
1587
1588         if (!ret->byref) {
1589                 if (ret->type == MONO_TYPE_I8 || ret->type == MONO_TYPE_U8) {
1590                         MonoInst *ins;
1591
1592                         if (COMPILE_LLVM (cfg)) {
1593                                 MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1594                         } else {
1595                                 MONO_INST_NEW (cfg, ins, OP_SETLRET);
1596                                 ins->sreg1 = val->dreg + 1;
1597                                 ins->sreg2 = val->dreg + 2;
1598                                 MONO_ADD_INS (cfg->cbb, ins);
1599                         }
1600                         return;
1601                 }
1602 #ifdef MONO_ARCH_SOFT_FLOAT
1603                 if (ret->type == MONO_TYPE_R8) {
1604                         MonoInst *ins;
1605
1606                         MONO_INST_NEW (cfg, ins, OP_SETFRET);
1607                         ins->dreg = cfg->ret->dreg;
1608                         ins->sreg1 = val->dreg;
1609                         MONO_ADD_INS (cfg->cbb, ins);
1610                         return;
1611                 }
1612                 if (ret->type == MONO_TYPE_R4) {
1613                         /* Already converted to an int in method_to_ir () */
1614                         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1615                         return;
1616                 }                       
1617 #elif defined(ARM_FPU_VFP)
1618                 if (ret->type == MONO_TYPE_R8 || ret->type == MONO_TYPE_R4) {
1619                         MonoInst *ins;
1620
1621                         MONO_INST_NEW (cfg, ins, OP_SETFRET);
1622                         ins->dreg = cfg->ret->dreg;
1623                         ins->sreg1 = val->dreg;
1624                         MONO_ADD_INS (cfg->cbb, ins);
1625                         return;
1626                 }
1627 #else
1628                 if (ret->type == MONO_TYPE_R4 || ret->type == MONO_TYPE_R8) {
1629                         MONO_EMIT_NEW_UNALU (cfg, OP_FMOVE, cfg->ret->dreg, val->dreg);
1630                         return;
1631                 }
1632 #endif
1633         }
1634
1635         /* FIXME: */
1636         MONO_EMIT_NEW_UNALU (cfg, OP_MOVE, cfg->ret->dreg, val->dreg);
1637 }
1638
1639 gboolean 
1640 mono_arch_is_inst_imm (gint64 imm)
1641 {
1642         return TRUE;
1643 }
1644
1645 #define DYN_CALL_STACK_ARGS 6
1646
1647 typedef struct {
1648         MonoMethodSignature *sig;
1649         CallInfo *cinfo;
1650 } ArchDynCallInfo;
1651
1652 typedef struct {
1653         mgreg_t regs [PARAM_REGS + DYN_CALL_STACK_ARGS];
1654         mgreg_t res, res2;
1655         guint8 *ret;
1656 } DynCallArgs;
1657
1658 static gboolean
1659 dyn_call_supported (CallInfo *cinfo, MonoMethodSignature *sig)
1660 {
1661         int i;
1662
1663         if (sig->hasthis + sig->param_count > PARAM_REGS + DYN_CALL_STACK_ARGS)
1664                 return FALSE;
1665
1666         switch (cinfo->ret.storage) {
1667         case RegTypeNone:
1668         case RegTypeGeneral:
1669         case RegTypeIRegPair:
1670         case RegTypeStructByAddr:
1671                 break;
1672         case RegTypeFP:
1673 #ifdef ARM_FPU_FPA
1674                 return FALSE;
1675 #elif defined(ARM_FPU_VFP)
1676                 break;
1677 #else
1678                 return FALSE;
1679 #endif
1680         default:
1681                 return FALSE;
1682         }
1683
1684         for (i = 0; i < cinfo->nargs; ++i) {
1685                 switch (cinfo->args [i].storage) {
1686                 case RegTypeGeneral:
1687                         break;
1688                 case RegTypeIRegPair:
1689                         break;
1690                 case RegTypeBase:
1691                         if (cinfo->args [i].offset >= (DYN_CALL_STACK_ARGS * sizeof (gpointer)))
1692                                 return FALSE;
1693                         break;
1694                 case RegTypeStructByVal:
1695                         if (cinfo->args [i].reg + cinfo->args [i].vtsize >= PARAM_REGS + DYN_CALL_STACK_ARGS)
1696                                 return FALSE;
1697                         break;
1698                 default:
1699                         return FALSE;
1700                 }
1701         }
1702
1703         // FIXME: Can't use cinfo only as it doesn't contain info about I8/float */
1704         for (i = 0; i < sig->param_count; ++i) {
1705                 MonoType *t = sig->params [i];
1706
1707                 if (t->byref)
1708                         continue;
1709
1710                 switch (t->type) {
1711                 case MONO_TYPE_R4:
1712                 case MONO_TYPE_R8:
1713 #ifdef MONO_ARCH_SOFT_FLOAT
1714                         return FALSE;
1715 #else
1716                         break;
1717 #endif
1718                         /*
1719                 case MONO_TYPE_I8:
1720                 case MONO_TYPE_U8:
1721                         return FALSE;
1722                         */
1723                 default:
1724                         break;
1725                 }
1726         }
1727
1728         return TRUE;
1729 }
1730
1731 MonoDynCallInfo*
1732 mono_arch_dyn_call_prepare (MonoMethodSignature *sig)
1733 {
1734         ArchDynCallInfo *info;
1735         CallInfo *cinfo;
1736
1737         cinfo = get_call_info (NULL, sig, FALSE);
1738
1739         if (!dyn_call_supported (cinfo, sig)) {
1740                 g_free (cinfo);
1741                 return NULL;
1742         }
1743
1744         info = g_new0 (ArchDynCallInfo, 1);
1745         // FIXME: Preprocess the info to speed up start_dyn_call ()
1746         info->sig = sig;
1747         info->cinfo = cinfo;
1748         
1749         return (MonoDynCallInfo*)info;
1750 }
1751
1752 void
1753 mono_arch_dyn_call_free (MonoDynCallInfo *info)
1754 {
1755         ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
1756
1757         g_free (ainfo->cinfo);
1758         g_free (ainfo);
1759 }
1760
1761 void
1762 mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, guint8 *buf, int buf_len)
1763 {
1764         ArchDynCallInfo *dinfo = (ArchDynCallInfo*)info;
1765         DynCallArgs *p = (DynCallArgs*)buf;
1766         int arg_index, greg, i, j;
1767         MonoMethodSignature *sig = dinfo->sig;
1768
1769         g_assert (buf_len >= sizeof (DynCallArgs));
1770
1771         p->res = 0;
1772         p->ret = ret;
1773
1774         arg_index = 0;
1775         greg = 0;
1776
1777         if (dinfo->cinfo->vtype_retaddr)
1778                 p->regs [greg ++] = (mgreg_t)ret;
1779
1780         if (sig->hasthis)
1781                 p->regs [greg ++] = (mgreg_t)*(args [arg_index ++]);
1782
1783         for (i = 0; i < sig->param_count; i++) {
1784                 MonoType *t = mono_type_get_underlying_type (sig->params [i]);
1785                 gpointer *arg = args [arg_index ++];
1786                 ArgInfo *ainfo = &dinfo->cinfo->args [i + sig->hasthis];
1787                 int slot = -1;
1788
1789                 if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair || ainfo->storage == RegTypeStructByVal)
1790                         slot = ainfo->reg;
1791                 else if (ainfo->storage == RegTypeBase)
1792                         slot = PARAM_REGS + (ainfo->offset / 4);
1793                 else
1794                         g_assert_not_reached ();
1795
1796                 if (t->byref) {
1797                         p->regs [slot] = (mgreg_t)*arg;
1798                         continue;
1799                 }
1800
1801                 switch (t->type) {
1802                 case MONO_TYPE_STRING:
1803                 case MONO_TYPE_CLASS:  
1804                 case MONO_TYPE_ARRAY:
1805                 case MONO_TYPE_SZARRAY:
1806                 case MONO_TYPE_OBJECT:
1807                 case MONO_TYPE_PTR:
1808                 case MONO_TYPE_I:
1809                 case MONO_TYPE_U:
1810                         p->regs [slot] = (mgreg_t)*arg;
1811                         break;
1812                 case MONO_TYPE_BOOLEAN:
1813                 case MONO_TYPE_U1:
1814                         p->regs [slot] = *(guint8*)arg;
1815                         break;
1816                 case MONO_TYPE_I1:
1817                         p->regs [slot] = *(gint8*)arg;
1818                         break;
1819                 case MONO_TYPE_I2:
1820                         p->regs [slot] = *(gint16*)arg;
1821                         break;
1822                 case MONO_TYPE_U2:
1823                 case MONO_TYPE_CHAR:
1824                         p->regs [slot] = *(guint16*)arg;
1825                         break;
1826                 case MONO_TYPE_I4:
1827                         p->regs [slot] = *(gint32*)arg;
1828                         break;
1829                 case MONO_TYPE_U4:
1830                         p->regs [slot] = *(guint32*)arg;
1831                         break;
1832                 case MONO_TYPE_I8:
1833                 case MONO_TYPE_U8:
1834                         p->regs [slot ++] = (mgreg_t)arg [0];
1835                         p->regs [slot] = (mgreg_t)arg [1];
1836                         break;
1837                 case MONO_TYPE_R4:
1838                         p->regs [slot] = *(mgreg_t*)arg;
1839                         break;
1840                 case MONO_TYPE_R8:
1841                         p->regs [slot ++] = (mgreg_t)arg [0];
1842                         p->regs [slot] = (mgreg_t)arg [1];
1843                         break;
1844                 case MONO_TYPE_GENERICINST:
1845                         if (MONO_TYPE_IS_REFERENCE (t)) {
1846                                 p->regs [slot] = (mgreg_t)*arg;
1847                                 break;
1848                         } else {
1849                                 /* Fall though */
1850                         }
1851                 case MONO_TYPE_VALUETYPE:
1852                         g_assert (ainfo->storage == RegTypeStructByVal);
1853
1854                         if (ainfo->size == 0)
1855                                 slot = PARAM_REGS + (ainfo->offset / 4);
1856                         else
1857                                 slot = ainfo->reg;
1858
1859                         for (j = 0; j < ainfo->size + ainfo->vtsize; ++j)
1860                                 p->regs [slot ++] = ((mgreg_t*)arg) [j];
1861                         break;
1862                 default:
1863                         g_assert_not_reached ();
1864                 }
1865         }
1866 }
1867
1868 void
1869 mono_arch_finish_dyn_call (MonoDynCallInfo *info, guint8 *buf)
1870 {
1871         ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info;
1872         MonoMethodSignature *sig = ((ArchDynCallInfo*)info)->sig;
1873         guint8 *ret = ((DynCallArgs*)buf)->ret;
1874         mgreg_t res = ((DynCallArgs*)buf)->res;
1875         mgreg_t res2 = ((DynCallArgs*)buf)->res2;
1876
1877         switch (mono_type_get_underlying_type (sig->ret)->type) {
1878         case MONO_TYPE_VOID:
1879                 *(gpointer*)ret = NULL;
1880                 break;
1881         case MONO_TYPE_STRING:
1882         case MONO_TYPE_CLASS:  
1883         case MONO_TYPE_ARRAY:
1884         case MONO_TYPE_SZARRAY:
1885         case MONO_TYPE_OBJECT:
1886         case MONO_TYPE_I:
1887         case MONO_TYPE_U:
1888         case MONO_TYPE_PTR:
1889                 *(gpointer*)ret = (gpointer)res;
1890                 break;
1891         case MONO_TYPE_I1:
1892                 *(gint8*)ret = res;
1893                 break;
1894         case MONO_TYPE_U1:
1895         case MONO_TYPE_BOOLEAN:
1896                 *(guint8*)ret = res;
1897                 break;
1898         case MONO_TYPE_I2:
1899                 *(gint16*)ret = res;
1900                 break;
1901         case MONO_TYPE_U2:
1902         case MONO_TYPE_CHAR:
1903                 *(guint16*)ret = res;
1904                 break;
1905         case MONO_TYPE_I4:
1906                 *(gint32*)ret = res;
1907                 break;
1908         case MONO_TYPE_U4:
1909                 *(guint32*)ret = res;
1910                 break;
1911         case MONO_TYPE_I8:
1912         case MONO_TYPE_U8:
1913                 /* This handles endianness as well */
1914                 ((gint32*)ret) [0] = res;
1915                 ((gint32*)ret) [1] = res2;
1916                 break;
1917         case MONO_TYPE_GENERICINST:
1918                 if (MONO_TYPE_IS_REFERENCE (sig->ret)) {
1919                         *(gpointer*)ret = (gpointer)res;
1920                         break;
1921                 } else {
1922                         /* Fall though */
1923                 }
1924         case MONO_TYPE_VALUETYPE:
1925                 g_assert (ainfo->cinfo->vtype_retaddr);
1926                 /* Nothing to do */
1927                 break;
1928 #if defined(ARM_FPU_VFP)
1929         case MONO_TYPE_R4:
1930                 *(float*)ret = *(float*)&res;
1931                 break;
1932         case MONO_TYPE_R8: {
1933                 mgreg_t regs [2];
1934
1935                 regs [0] = res;
1936                 regs [1] = res2;
1937
1938                 *(double*)ret = *(double*)&regs;
1939                 break;
1940         }
1941 #endif
1942         default:
1943                 g_assert_not_reached ();
1944         }
1945 }
1946
1947 /*
1948  * Allow tracing to work with this interface (with an optional argument)
1949  */
1950
1951 void*
1952 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
1953 {
1954         guchar *code = p;
1955
1956         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
1957         ARM_MOV_REG_IMM8 (code, ARMREG_R1, 0); /* NULL ebp for now */
1958         code = mono_arm_emit_load_imm (code, ARMREG_R2, (guint32)func);
1959         code = emit_call_reg (code, ARMREG_R2);
1960         return code;
1961 }
1962
1963 enum {
1964         SAVE_NONE,
1965         SAVE_STRUCT,
1966         SAVE_ONE,
1967         SAVE_TWO,
1968         SAVE_FP
1969 };
1970
1971 void*
1972 mono_arch_instrument_epilog_full (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments, gboolean preserve_argument_registers)
1973 {
1974         guchar *code = p;
1975         int save_mode = SAVE_NONE;
1976         int offset;
1977         MonoMethod *method = cfg->method;
1978         int rtype = mini_type_get_underlying_type (cfg->generic_sharing_context, mono_method_signature (method)->ret)->type;
1979         int save_offset = cfg->param_area;
1980         save_offset += 7;
1981         save_offset &= ~7;
1982         
1983         offset = code - cfg->native_code;
1984         /* we need about 16 instructions */
1985         if (offset > (cfg->code_size - 16 * 4)) {
1986                 cfg->code_size *= 2;
1987                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1988                 code = cfg->native_code + offset;
1989         }
1990         switch (rtype) {
1991         case MONO_TYPE_VOID:
1992                 /* special case string .ctor icall */
1993                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
1994                         save_mode = SAVE_ONE;
1995                 else
1996                         save_mode = SAVE_NONE;
1997                 break;
1998         case MONO_TYPE_I8:
1999         case MONO_TYPE_U8:
2000                 save_mode = SAVE_TWO;
2001                 break;
2002         case MONO_TYPE_R4:
2003         case MONO_TYPE_R8:
2004                 save_mode = SAVE_FP;
2005                 break;
2006         case MONO_TYPE_VALUETYPE:
2007                 save_mode = SAVE_STRUCT;
2008                 break;
2009         default:
2010                 save_mode = SAVE_ONE;
2011                 break;
2012         }
2013
2014         switch (save_mode) {
2015         case SAVE_TWO:
2016                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
2017                 ARM_STR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
2018                 if (enable_arguments) {
2019                         ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_R1);
2020                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
2021                 }
2022                 break;
2023         case SAVE_ONE:
2024                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
2025                 if (enable_arguments) {
2026                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
2027                 }
2028                 break;
2029         case SAVE_FP:
2030                 /* FIXME: what reg?  */
2031                 if (enable_arguments) {
2032                         /* FIXME: what reg?  */
2033                 }
2034                 break;
2035         case SAVE_STRUCT:
2036                 if (enable_arguments) {
2037                         /* FIXME: get the actual address  */
2038                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
2039                 }
2040                 break;
2041         case SAVE_NONE:
2042         default:
2043                 break;
2044         }
2045
2046         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
2047         code = mono_arm_emit_load_imm (code, ARMREG_IP, (guint32)func);
2048         code = emit_call_reg (code, ARMREG_IP);
2049
2050         switch (save_mode) {
2051         case SAVE_TWO:
2052                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
2053                 ARM_LDR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
2054                 break;
2055         case SAVE_ONE:
2056                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
2057                 break;
2058         case SAVE_FP:
2059                 /* FIXME */
2060                 break;
2061         case SAVE_NONE:
2062         default:
2063                 break;
2064         }
2065
2066         return code;
2067 }
2068
2069 /*
2070  * The immediate field for cond branches is big enough for all reasonable methods
2071  */
2072 #define EMIT_COND_BRANCH_FLAGS(ins,condcode) \
2073 if (0 && ins->inst_true_bb->native_offset) { \
2074         ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffffff); \
2075 } else { \
2076         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
2077         ARM_B_COND (code, (condcode), 0);       \
2078 }
2079
2080 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_cc_table [(cond)])
2081
2082 /* emit an exception if condition is fail
2083  *
2084  * We assign the extra code used to throw the implicit exceptions
2085  * to cfg->bb_exit as far as the big branch handling is concerned
2086  */
2087 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(condcode,exc_name)            \
2088         do {                                                        \
2089                 mono_add_patch_info (cfg, code - cfg->native_code,   \
2090                                     MONO_PATCH_INFO_EXC, exc_name);  \
2091                 ARM_BL_COND (code, (condcode), 0);      \
2092         } while (0); 
2093
2094 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_cc_table [(cond)], (exc_name))
2095
2096 void
2097 mono_arch_peephole_pass_1 (MonoCompile *cfg, MonoBasicBlock *bb)
2098 {
2099 }
2100
2101 void
2102 mono_arch_peephole_pass_2 (MonoCompile *cfg, MonoBasicBlock *bb)
2103 {
2104         MonoInst *ins, *n, *last_ins = NULL;
2105
2106         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
2107                 switch (ins->opcode) {
2108                 case OP_MUL_IMM: 
2109                 case OP_IMUL_IMM: 
2110                         /* Already done by an arch-independent pass */
2111                         break;
2112                 case OP_LOAD_MEMBASE:
2113                 case OP_LOADI4_MEMBASE:
2114                         /* 
2115                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
2116                          * OP_LOAD_MEMBASE offset(basereg), reg
2117                          */
2118                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
2119                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
2120                             ins->inst_basereg == last_ins->inst_destbasereg &&
2121                             ins->inst_offset == last_ins->inst_offset) {
2122                                 if (ins->dreg == last_ins->sreg1) {
2123                                         MONO_DELETE_INS (bb, ins);
2124                                         continue;
2125                                 } else {
2126                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2127                                         ins->opcode = OP_MOVE;
2128                                         ins->sreg1 = last_ins->sreg1;
2129                                 }
2130
2131                         /* 
2132                          * Note: reg1 must be different from the basereg in the second load
2133                          * OP_LOAD_MEMBASE offset(basereg), reg1
2134                          * OP_LOAD_MEMBASE offset(basereg), reg2
2135                          * -->
2136                          * OP_LOAD_MEMBASE offset(basereg), reg1
2137                          * OP_MOVE reg1, reg2
2138                          */
2139                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
2140                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
2141                               ins->inst_basereg != last_ins->dreg &&
2142                               ins->inst_basereg == last_ins->inst_basereg &&
2143                               ins->inst_offset == last_ins->inst_offset) {
2144
2145                                 if (ins->dreg == last_ins->dreg) {
2146                                         MONO_DELETE_INS (bb, ins);
2147                                         continue;
2148                                 } else {
2149                                         ins->opcode = OP_MOVE;
2150                                         ins->sreg1 = last_ins->dreg;
2151                                 }
2152
2153                                 //g_assert_not_reached ();
2154
2155 #if 0
2156                         /* 
2157                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
2158                          * OP_LOAD_MEMBASE offset(basereg), reg
2159                          * -->
2160                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
2161                          * OP_ICONST reg, imm
2162                          */
2163                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
2164                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
2165                                    ins->inst_basereg == last_ins->inst_destbasereg &&
2166                                    ins->inst_offset == last_ins->inst_offset) {
2167                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
2168                                 ins->opcode = OP_ICONST;
2169                                 ins->inst_c0 = last_ins->inst_imm;
2170                                 g_assert_not_reached (); // check this rule
2171 #endif
2172                         }
2173                         break;
2174                 case OP_LOADU1_MEMBASE:
2175                 case OP_LOADI1_MEMBASE:
2176                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
2177                                         ins->inst_basereg == last_ins->inst_destbasereg &&
2178                                         ins->inst_offset == last_ins->inst_offset) {
2179                                 ins->opcode = (ins->opcode == OP_LOADI1_MEMBASE) ? OP_ICONV_TO_I1 : OP_ICONV_TO_U1;
2180                                 ins->sreg1 = last_ins->sreg1;                           
2181                         }
2182                         break;
2183                 case OP_LOADU2_MEMBASE:
2184                 case OP_LOADI2_MEMBASE:
2185                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
2186                                         ins->inst_basereg == last_ins->inst_destbasereg &&
2187                                         ins->inst_offset == last_ins->inst_offset) {
2188                                 ins->opcode = (ins->opcode == OP_LOADI2_MEMBASE) ? OP_ICONV_TO_I2 : OP_ICONV_TO_U2;
2189                                 ins->sreg1 = last_ins->sreg1;                           
2190                         }
2191                         break;
2192                 case OP_MOVE:
2193                         ins->opcode = OP_MOVE;
2194                         /* 
2195                          * OP_MOVE reg, reg 
2196                          */
2197                         if (ins->dreg == ins->sreg1) {
2198                                 MONO_DELETE_INS (bb, ins);
2199                                 continue;
2200                         }
2201                         /* 
2202                          * OP_MOVE sreg, dreg 
2203                          * OP_MOVE dreg, sreg
2204                          */
2205                         if (last_ins && last_ins->opcode == OP_MOVE &&
2206                             ins->sreg1 == last_ins->dreg &&
2207                             ins->dreg == last_ins->sreg1) {
2208                                 MONO_DELETE_INS (bb, ins);
2209                                 continue;
2210                         }
2211                         break;
2212                 }
2213                 last_ins = ins;
2214                 ins = ins->next;
2215         }
2216         bb->last_ins = last_ins;
2217 }
2218
2219 /* 
2220  * the branch_cc_table should maintain the order of these
2221  * opcodes.
2222 case CEE_BEQ:
2223 case CEE_BGE:
2224 case CEE_BGT:
2225 case CEE_BLE:
2226 case CEE_BLT:
2227 case CEE_BNE_UN:
2228 case CEE_BGE_UN:
2229 case CEE_BGT_UN:
2230 case CEE_BLE_UN:
2231 case CEE_BLT_UN:
2232  */
2233 static const guchar 
2234 branch_cc_table [] = {
2235         ARMCOND_EQ, 
2236         ARMCOND_GE, 
2237         ARMCOND_GT, 
2238         ARMCOND_LE,
2239         ARMCOND_LT, 
2240         
2241         ARMCOND_NE, 
2242         ARMCOND_HS, 
2243         ARMCOND_HI, 
2244         ARMCOND_LS,
2245         ARMCOND_LO
2246 };
2247
2248 #define NEW_INS(cfg,dest,op) do {       \
2249                 MONO_INST_NEW ((cfg), (dest), (op)); \
2250         mono_bblock_insert_before_ins (bb, ins, (dest)); \
2251         } while (0)
2252
2253 static int
2254 map_to_reg_reg_op (int op)
2255 {
2256         switch (op) {
2257         case OP_ADD_IMM:
2258                 return OP_IADD;
2259         case OP_SUB_IMM:
2260                 return OP_ISUB;
2261         case OP_AND_IMM:
2262                 return OP_IAND;
2263         case OP_COMPARE_IMM:
2264                 return OP_COMPARE;
2265         case OP_ICOMPARE_IMM:
2266                 return OP_ICOMPARE;
2267         case OP_ADDCC_IMM:
2268                 return OP_ADDCC;
2269         case OP_ADC_IMM:
2270                 return OP_ADC;
2271         case OP_SUBCC_IMM:
2272                 return OP_SUBCC;
2273         case OP_SBB_IMM:
2274                 return OP_SBB;
2275         case OP_OR_IMM:
2276                 return OP_IOR;
2277         case OP_XOR_IMM:
2278                 return OP_IXOR;
2279         case OP_LOAD_MEMBASE:
2280                 return OP_LOAD_MEMINDEX;
2281         case OP_LOADI4_MEMBASE:
2282                 return OP_LOADI4_MEMINDEX;
2283         case OP_LOADU4_MEMBASE:
2284                 return OP_LOADU4_MEMINDEX;
2285         case OP_LOADU1_MEMBASE:
2286                 return OP_LOADU1_MEMINDEX;
2287         case OP_LOADI2_MEMBASE:
2288                 return OP_LOADI2_MEMINDEX;
2289         case OP_LOADU2_MEMBASE:
2290                 return OP_LOADU2_MEMINDEX;
2291         case OP_LOADI1_MEMBASE:
2292                 return OP_LOADI1_MEMINDEX;
2293         case OP_STOREI1_MEMBASE_REG:
2294                 return OP_STOREI1_MEMINDEX;
2295         case OP_STOREI2_MEMBASE_REG:
2296                 return OP_STOREI2_MEMINDEX;
2297         case OP_STOREI4_MEMBASE_REG:
2298                 return OP_STOREI4_MEMINDEX;
2299         case OP_STORE_MEMBASE_REG:
2300                 return OP_STORE_MEMINDEX;
2301         case OP_STORER4_MEMBASE_REG:
2302                 return OP_STORER4_MEMINDEX;
2303         case OP_STORER8_MEMBASE_REG:
2304                 return OP_STORER8_MEMINDEX;
2305         case OP_STORE_MEMBASE_IMM:
2306                 return OP_STORE_MEMBASE_REG;
2307         case OP_STOREI1_MEMBASE_IMM:
2308                 return OP_STOREI1_MEMBASE_REG;
2309         case OP_STOREI2_MEMBASE_IMM:
2310                 return OP_STOREI2_MEMBASE_REG;
2311         case OP_STOREI4_MEMBASE_IMM:
2312                 return OP_STOREI4_MEMBASE_REG;
2313         }
2314         g_assert_not_reached ();
2315 }
2316
2317 /*
2318  * Remove from the instruction list the instructions that can't be
2319  * represented with very simple instructions with no register
2320  * requirements.
2321  */
2322 void
2323 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
2324 {
2325         MonoInst *ins, *temp, *last_ins = NULL;
2326         int rot_amount, imm8, low_imm;
2327
2328         MONO_BB_FOR_EACH_INS (bb, ins) {
2329 loop_start:
2330                 switch (ins->opcode) {
2331                 case OP_ADD_IMM:
2332                 case OP_SUB_IMM:
2333                 case OP_AND_IMM:
2334                 case OP_COMPARE_IMM:
2335                 case OP_ICOMPARE_IMM:
2336                 case OP_ADDCC_IMM:
2337                 case OP_ADC_IMM:
2338                 case OP_SUBCC_IMM:
2339                 case OP_SBB_IMM:
2340                 case OP_OR_IMM:
2341                 case OP_XOR_IMM:
2342                 case OP_IADD_IMM:
2343                 case OP_ISUB_IMM:
2344                 case OP_IAND_IMM:
2345                 case OP_IADC_IMM:
2346                 case OP_ISBB_IMM:
2347                 case OP_IOR_IMM:
2348                 case OP_IXOR_IMM:
2349                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
2350                                 NEW_INS (cfg, temp, OP_ICONST);
2351                                 temp->inst_c0 = ins->inst_imm;
2352                                 temp->dreg = mono_alloc_ireg (cfg);
2353                                 ins->sreg2 = temp->dreg;
2354                                 ins->opcode = mono_op_imm_to_op (ins->opcode);
2355                         }
2356                         if (ins->opcode == OP_SBB || ins->opcode == OP_ISBB || ins->opcode == OP_SUBCC)
2357                                 goto loop_start;
2358                         else
2359                                 break;
2360                 case OP_MUL_IMM:
2361                 case OP_IMUL_IMM:
2362                         if (ins->inst_imm == 1) {
2363                                 ins->opcode = OP_MOVE;
2364                                 break;
2365                         }
2366                         if (ins->inst_imm == 0) {
2367                                 ins->opcode = OP_ICONST;
2368                                 ins->inst_c0 = 0;
2369                                 break;
2370                         }
2371                         imm8 = mono_is_power_of_two (ins->inst_imm);
2372                         if (imm8 > 0) {
2373                                 ins->opcode = OP_SHL_IMM;
2374                                 ins->inst_imm = imm8;
2375                                 break;
2376                         }
2377                         NEW_INS (cfg, temp, OP_ICONST);
2378                         temp->inst_c0 = ins->inst_imm;
2379                         temp->dreg = mono_alloc_ireg (cfg);
2380                         ins->sreg2 = temp->dreg;
2381                         ins->opcode = OP_IMUL;
2382                         break;
2383                 case OP_SBB:
2384                 case OP_ISBB:
2385                 case OP_SUBCC:
2386                 case OP_ISUBCC:
2387                         if (ins->next  && (ins->next->opcode == OP_COND_EXC_C || ins->next->opcode == OP_COND_EXC_IC))
2388                                 /* ARM sets the C flag to 1 if there was _no_ overflow */
2389                                 ins->next->opcode = OP_COND_EXC_NC;
2390                         break;
2391                 case OP_LOCALLOC_IMM:
2392                         NEW_INS (cfg, temp, OP_ICONST);
2393                         temp->inst_c0 = ins->inst_imm;
2394                         temp->dreg = mono_alloc_ireg (cfg);
2395                         ins->sreg1 = temp->dreg;
2396                         ins->opcode = OP_LOCALLOC;
2397                         break;
2398                 case OP_LOAD_MEMBASE:
2399                 case OP_LOADI4_MEMBASE:
2400                 case OP_LOADU4_MEMBASE:
2401                 case OP_LOADU1_MEMBASE:
2402                         /* we can do two things: load the immed in a register
2403                          * and use an indexed load, or see if the immed can be
2404                          * represented as an ad_imm + a load with a smaller offset
2405                          * that fits. We just do the first for now, optimize later.
2406                          */
2407                         if (arm_is_imm12 (ins->inst_offset))
2408                                 break;
2409                         NEW_INS (cfg, temp, OP_ICONST);
2410                         temp->inst_c0 = ins->inst_offset;
2411                         temp->dreg = mono_alloc_ireg (cfg);
2412                         ins->sreg2 = temp->dreg;
2413                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2414                         break;
2415                 case OP_LOADI2_MEMBASE:
2416                 case OP_LOADU2_MEMBASE:
2417                 case OP_LOADI1_MEMBASE:
2418                         if (arm_is_imm8 (ins->inst_offset))
2419                                 break;
2420                         NEW_INS (cfg, temp, OP_ICONST);
2421                         temp->inst_c0 = ins->inst_offset;
2422                         temp->dreg = mono_alloc_ireg (cfg);
2423                         ins->sreg2 = temp->dreg;
2424                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2425                         break;
2426                 case OP_LOADR4_MEMBASE:
2427                 case OP_LOADR8_MEMBASE:
2428                         if (arm_is_fpimm8 (ins->inst_offset))
2429                                 break;
2430                         low_imm = ins->inst_offset & 0x1ff;
2431                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~0x1ff, &rot_amount)) >= 0) {
2432                                 NEW_INS (cfg, temp, OP_ADD_IMM);
2433                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
2434                                 temp->sreg1 = ins->inst_basereg;
2435                                 temp->dreg = mono_alloc_ireg (cfg);
2436                                 ins->inst_basereg = temp->dreg;
2437                                 ins->inst_offset = low_imm;
2438                                 break;
2439                         }
2440                         /* VFP/FPA doesn't have indexed load instructions */
2441                         g_assert_not_reached ();
2442                         break;
2443                 case OP_STORE_MEMBASE_REG:
2444                 case OP_STOREI4_MEMBASE_REG:
2445                 case OP_STOREI1_MEMBASE_REG:
2446                         if (arm_is_imm12 (ins->inst_offset))
2447                                 break;
2448                         NEW_INS (cfg, temp, OP_ICONST);
2449                         temp->inst_c0 = ins->inst_offset;
2450                         temp->dreg = mono_alloc_ireg (cfg);
2451                         ins->sreg2 = temp->dreg;
2452                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2453                         break;
2454                 case OP_STOREI2_MEMBASE_REG:
2455                         if (arm_is_imm8 (ins->inst_offset))
2456                                 break;
2457                         NEW_INS (cfg, temp, OP_ICONST);
2458                         temp->inst_c0 = ins->inst_offset;
2459                         temp->dreg = mono_alloc_ireg (cfg);
2460                         ins->sreg2 = temp->dreg;
2461                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2462                         break;
2463                 case OP_STORER4_MEMBASE_REG:
2464                 case OP_STORER8_MEMBASE_REG:
2465                         if (arm_is_fpimm8 (ins->inst_offset))
2466                                 break;
2467                         low_imm = ins->inst_offset & 0x1ff;
2468                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~ 0x1ff, &rot_amount)) >= 0 && arm_is_fpimm8 (low_imm)) {
2469                                 NEW_INS (cfg, temp, OP_ADD_IMM);
2470                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
2471                                 temp->sreg1 = ins->inst_destbasereg;
2472                                 temp->dreg = mono_alloc_ireg (cfg);
2473                                 ins->inst_destbasereg = temp->dreg;
2474                                 ins->inst_offset = low_imm;
2475                                 break;
2476                         }
2477                         /*g_print ("fail with: %d (%d, %d)\n", ins->inst_offset, ins->inst_offset & ~0x1ff, low_imm);*/
2478                         /* VFP/FPA doesn't have indexed store instructions */
2479                         g_assert_not_reached ();
2480                         break;
2481                 case OP_STORE_MEMBASE_IMM:
2482                 case OP_STOREI1_MEMBASE_IMM:
2483                 case OP_STOREI2_MEMBASE_IMM:
2484                 case OP_STOREI4_MEMBASE_IMM:
2485                         NEW_INS (cfg, temp, OP_ICONST);
2486                         temp->inst_c0 = ins->inst_imm;
2487                         temp->dreg = mono_alloc_ireg (cfg);
2488                         ins->sreg1 = temp->dreg;
2489                         ins->opcode = map_to_reg_reg_op (ins->opcode);
2490                         last_ins = temp;
2491                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
2492                 case OP_FCOMPARE: {
2493                         gboolean swap = FALSE;
2494                         int reg;
2495
2496                         if (!ins->next) {
2497                                 /* Optimized away */
2498                                 NULLIFY_INS (ins);
2499                                 break;
2500                         }
2501
2502                         /* Some fp compares require swapped operands */
2503                         switch (ins->next->opcode) {
2504                         case OP_FBGT:
2505                                 ins->next->opcode = OP_FBLT;
2506                                 swap = TRUE;
2507                                 break;
2508                         case OP_FBGT_UN:
2509                                 ins->next->opcode = OP_FBLT_UN;
2510                                 swap = TRUE;
2511                                 break;
2512                         case OP_FBLE:
2513                                 ins->next->opcode = OP_FBGE;
2514                                 swap = TRUE;
2515                                 break;
2516                         case OP_FBLE_UN:
2517                                 ins->next->opcode = OP_FBGE_UN;
2518                                 swap = TRUE;
2519                                 break;
2520                         default:
2521                                 break;
2522                         }
2523                         if (swap) {
2524                                 reg = ins->sreg1;
2525                                 ins->sreg1 = ins->sreg2;
2526                                 ins->sreg2 = reg;
2527                         }
2528                         break;
2529                 }
2530                 }
2531
2532                 last_ins = ins;
2533         }
2534         bb->last_ins = last_ins;
2535         bb->max_vreg = cfg->next_vreg;
2536 }
2537
2538 void
2539 mono_arch_decompose_long_opts (MonoCompile *cfg, MonoInst *long_ins)
2540 {
2541         MonoInst *ins;
2542
2543         if (long_ins->opcode == OP_LNEG) {
2544                 ins = long_ins;
2545                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSBS_IMM, ins->dreg + 1, ins->sreg1 + 1, 0);
2546                 MONO_EMIT_NEW_BIALU_IMM (cfg, OP_ARM_RSC_IMM, ins->dreg + 2, ins->sreg1 + 2, 0);
2547                 NULLIFY_INS (ins);
2548         }
2549 }
2550
2551 static guchar*
2552 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
2553 {
2554         /* sreg is a float, dreg is an integer reg  */
2555 #ifdef ARM_FPU_FPA
2556         ARM_FIXZ (code, dreg, sreg);
2557 #elif defined(ARM_FPU_VFP)
2558         if (is_signed)
2559                 ARM_TOSIZD (code, ARM_VFP_F0, sreg);
2560         else
2561                 ARM_TOUIZD (code, ARM_VFP_F0, sreg);
2562         ARM_FMRS (code, dreg, ARM_VFP_F0);
2563 #endif
2564         if (!is_signed) {
2565                 if (size == 1)
2566                         ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff);
2567                 else if (size == 2) {
2568                         ARM_SHL_IMM (code, dreg, dreg, 16);
2569                         ARM_SHR_IMM (code, dreg, dreg, 16);
2570                 }
2571         } else {
2572                 if (size == 1) {
2573                         ARM_SHL_IMM (code, dreg, dreg, 24);
2574                         ARM_SAR_IMM (code, dreg, dreg, 24);
2575                 } else if (size == 2) {
2576                         ARM_SHL_IMM (code, dreg, dreg, 16);
2577                         ARM_SAR_IMM (code, dreg, dreg, 16);
2578                 }
2579         }
2580         return code;
2581 }
2582
2583 typedef struct {
2584         guchar *code;
2585         const guchar *target;
2586         int absolute;
2587         int found;
2588 } PatchData;
2589
2590 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
2591
2592 static int
2593 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
2594         PatchData *pdata = (PatchData*)user_data;
2595         guchar *code = data;
2596         guint32 *thunks = data;
2597         guint32 *endthunks = (guint32*)(code + bsize);
2598         int count = 0;
2599         int difflow, diffhigh;
2600
2601         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
2602         difflow = (char*)pdata->code - (char*)thunks;
2603         diffhigh = (char*)pdata->code - (char*)endthunks;
2604         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
2605                 return 0;
2606
2607         /*
2608          * The thunk is composed of 3 words:
2609          * load constant from thunks [2] into ARM_IP
2610          * bx to ARM_IP
2611          * address constant
2612          * Note that the LR register is already setup
2613          */
2614         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
2615         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
2616                 while (thunks < endthunks) {
2617                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
2618                         if (thunks [2] == (guint32)pdata->target) {
2619                                 arm_patch (pdata->code, (guchar*)thunks);
2620                                 mono_arch_flush_icache (pdata->code, 4);
2621                                 pdata->found = 1;
2622                                 return 1;
2623                         } else if ((thunks [0] == 0) && (thunks [1] == 0) && (thunks [2] == 0)) {
2624                                 /* found a free slot instead: emit thunk */
2625                                 /* ARMREG_IP is fine to use since this can't be an IMT call
2626                                  * which is indirect
2627                                  */
2628                                 code = (guchar*)thunks;
2629                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
2630                                 if (thumb_supported)
2631                                         ARM_BX (code, ARMREG_IP);
2632                                 else
2633                                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2634                                 thunks [2] = (guint32)pdata->target;
2635                                 mono_arch_flush_icache ((guchar*)thunks, 12);
2636
2637                                 arm_patch (pdata->code, (guchar*)thunks);
2638                                 mono_arch_flush_icache (pdata->code, 4);
2639                                 pdata->found = 1;
2640                                 return 1;
2641                         }
2642                         /* skip 12 bytes, the size of the thunk */
2643                         thunks += 3;
2644                         count++;
2645                 }
2646                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
2647         }
2648         return 0;
2649 }
2650
2651 static void
2652 handle_thunk (MonoDomain *domain, int absolute, guchar *code, const guchar *target)
2653 {
2654         PatchData pdata;
2655
2656         if (!domain)
2657                 domain = mono_domain_get ();
2658
2659         pdata.code = code;
2660         pdata.target = target;
2661         pdata.absolute = absolute;
2662         pdata.found = 0;
2663
2664         mono_domain_lock (domain);
2665         mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2666
2667         if (!pdata.found) {
2668                 /* this uses the first available slot */
2669                 pdata.found = 2;
2670                 mono_domain_code_foreach (domain, search_thunk_slot, &pdata);
2671         }
2672         mono_domain_unlock (domain);
2673
2674         if (pdata.found != 1)
2675                 g_print ("thunk failed for %p from %p\n", target, code);
2676         g_assert (pdata.found == 1);
2677 }
2678
2679 static void
2680 arm_patch_general (MonoDomain *domain, guchar *code, const guchar *target)
2681 {
2682         guint32 *code32 = (void*)code;
2683         guint32 ins = *code32;
2684         guint32 prim = (ins >> 25) & 7;
2685         guint32 tval = GPOINTER_TO_UINT (target);
2686
2687         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
2688         if (prim == 5) { /* 101b */
2689                 /* the diff starts 8 bytes from the branch opcode */
2690                 gint diff = target - code - 8;
2691                 gint tbits;
2692                 gint tmask = 0xffffffff;
2693                 if (tval & 1) { /* entering thumb mode */
2694                         diff = target - 1 - code - 8;
2695                         g_assert (thumb_supported);
2696                         tbits = 0xf << 28; /* bl->blx bit pattern */
2697                         g_assert ((ins & (1 << 24))); /* it must be a bl, not b instruction */
2698                         /* this low bit of the displacement is moved to bit 24 in the instruction encoding */
2699                         if (diff & 2) {
2700                                 tbits |= 1 << 24;
2701                         }
2702                         tmask = ~(1 << 24); /* clear the link bit */
2703                         /*g_print ("blx to thumb: target: %p, code: %p, diff: %d, mask: %x\n", target, code, diff, tmask);*/
2704                 } else {
2705                         tbits = 0;
2706                 }
2707                 if (diff >= 0) {
2708                         if (diff <= 33554431) {
2709                                 diff >>= 2;
2710                                 ins = (ins & 0xff000000) | diff;
2711                                 ins &= tmask;
2712                                 *code32 = ins | tbits;
2713                                 return;
2714                         }
2715                 } else {
2716                         /* diff between 0 and -33554432 */
2717                         if (diff >= -33554432) {
2718                                 diff >>= 2;
2719                                 ins = (ins & 0xff000000) | (diff & ~0xff000000);
2720                                 ins &= tmask;
2721                                 *code32 = ins | tbits;
2722                                 return;
2723                         }
2724                 }
2725                 
2726                 handle_thunk (domain, TRUE, code, target);
2727                 return;
2728         }
2729
2730         /*
2731          * The alternative call sequences looks like this:
2732          *
2733          *      ldr ip, [pc] // loads the address constant
2734          *      b 1f         // jumps around the constant
2735          *      address constant embedded in the code
2736          *   1f:
2737          *      mov lr, pc
2738          *      mov pc, ip
2739          *
2740          * There are two cases for patching:
2741          * a) at the end of method emission: in this case code points to the start
2742          *    of the call sequence
2743          * b) during runtime patching of the call site: in this case code points
2744          *    to the mov pc, ip instruction
2745          *
2746          * We have to handle also the thunk jump code sequence:
2747          *
2748          *      ldr ip, [pc]
2749          *      mov pc, ip
2750          *      address constant // execution never reaches here
2751          */
2752         if ((ins & 0x0ffffff0) == 0x12fff10) {
2753                 /* Branch and exchange: the address is constructed in a reg 
2754                  * We can patch BX when the code sequence is the following:
2755                  *  ldr     ip, [pc, #0]    ; 0x8
2756                  *  b       0xc
2757                  *  .word code_ptr
2758                  *  mov     lr, pc
2759                  *  bx      ips
2760                  * */
2761                 guint32 ccode [4];
2762                 guint8 *emit = (guint8*)ccode;
2763                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
2764                 ARM_B (emit, 0);
2765                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
2766                 ARM_BX (emit, ARMREG_IP);
2767
2768                 /*patching from magic trampoline*/
2769                 if (ins == ccode [3]) {
2770                         g_assert (code32 [-4] == ccode [0]);
2771                         g_assert (code32 [-3] == ccode [1]);
2772                         g_assert (code32 [-1] == ccode [2]);
2773                         code32 [-2] = (guint32)target;
2774                         return;
2775                 }
2776                 /*patching from JIT*/
2777                 if (ins == ccode [0]) {
2778                         g_assert (code32 [1] == ccode [1]);
2779                         g_assert (code32 [3] == ccode [2]);
2780                         g_assert (code32 [4] == ccode [3]);
2781                         code32 [2] = (guint32)target;
2782                         return;
2783                 }
2784                 g_assert_not_reached ();
2785         } else if ((ins & 0x0ffffff0) == 0x12fff30) {
2786                 /*
2787                  * ldr ip, [pc, #0]
2788                  * b 0xc
2789                  * .word code_ptr
2790                  * blx ip
2791                  */
2792                 guint32 ccode [4];
2793                 guint8 *emit = (guint8*)ccode;
2794                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
2795                 ARM_B (emit, 0);
2796                 ARM_BLX_REG (emit, ARMREG_IP);
2797
2798                 g_assert (code32 [-3] == ccode [0]);
2799                 g_assert (code32 [-2] == ccode [1]);
2800                 g_assert (code32 [0] == ccode [2]);
2801
2802                 code32 [-1] = (guint32)target;
2803         } else {
2804                 guint32 ccode [4];
2805                 guint32 *tmp = ccode;
2806                 guint8 *emit = (guint8*)tmp;
2807                 ARM_LDR_IMM (emit, ARMREG_IP, ARMREG_PC, 0);
2808                 ARM_MOV_REG_REG (emit, ARMREG_LR, ARMREG_PC);
2809                 ARM_MOV_REG_REG (emit, ARMREG_PC, ARMREG_IP);
2810                 ARM_BX (emit, ARMREG_IP);
2811                 if (ins == ccode [2]) {
2812                         g_assert_not_reached (); // should be -2 ...
2813                         code32 [-1] = (guint32)target;
2814                         return;
2815                 }
2816                 if (ins == ccode [0]) {
2817                         /* handles both thunk jump code and the far call sequence */
2818                         code32 [2] = (guint32)target;
2819                         return;
2820                 }
2821                 g_assert_not_reached ();
2822         }
2823 //      g_print ("patched with 0x%08x\n", ins);
2824 }
2825
2826 void
2827 arm_patch (guchar *code, const guchar *target)
2828 {
2829         arm_patch_general (NULL, code, target);
2830 }
2831
2832 /* 
2833  * Return the >= 0 uimm8 value if val can be represented with a byte + rotation
2834  * (with the rotation amount in *rot_amount. rot_amount is already adjusted
2835  * to be used with the emit macros.
2836  * Return -1 otherwise.
2837  */
2838 int
2839 mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount)
2840 {
2841         guint32 res, i;
2842         for (i = 0; i < 31; i+= 2) {
2843                 res = (val << (32 - i)) | (val >> i);
2844                 if (res & ~0xff)
2845                         continue;
2846                 *rot_amount = i? 32 - i: 0;
2847                 return res;
2848         }
2849         return -1;
2850 }
2851
2852 /*
2853  * Emits in code a sequence of instructions that load the value 'val'
2854  * into the dreg register. Uses at most 4 instructions.
2855  */
2856 guint8*
2857 mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
2858 {
2859         int imm8, rot_amount;
2860 #if 0
2861         ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
2862         /* skip the constant pool */
2863         ARM_B (code, 0);
2864         *(int*)code = val;
2865         code += 4;
2866         return code;
2867 #endif
2868         if ((imm8 = mono_arm_is_rotated_imm8 (val, &rot_amount)) >= 0) {
2869                 ARM_MOV_REG_IMM (code, dreg, imm8, rot_amount);
2870         } else if ((imm8 = mono_arm_is_rotated_imm8 (~val, &rot_amount)) >= 0) {
2871                 ARM_MVN_REG_IMM (code, dreg, imm8, rot_amount);
2872         } else {
2873                 if (v7_supported) {
2874                         ARM_MOVW_REG_IMM (code, dreg, val & 0xffff);
2875                         if (val >> 16)
2876                                 ARM_MOVT_REG_IMM (code, dreg, (val >> 16) & 0xffff);
2877                         return code;
2878                 }
2879                 if (val & 0xFF) {
2880                         ARM_MOV_REG_IMM8 (code, dreg, (val & 0xFF));
2881                         if (val & 0xFF00) {
2882                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
2883                         }
2884                         if (val & 0xFF0000) {
2885                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
2886                         }
2887                         if (val & 0xFF000000) {
2888                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
2889                         }
2890                 } else if (val & 0xFF00) {
2891                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF00) >> 8, 24);
2892                         if (val & 0xFF0000) {
2893                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
2894                         }
2895                         if (val & 0xFF000000) {
2896                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
2897                         }
2898                 } else if (val & 0xFF0000) {
2899                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF0000) >> 16, 16);
2900                         if (val & 0xFF000000) {
2901                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
2902                         }
2903                 }
2904                 //g_assert_not_reached ();
2905         }
2906         return code;
2907 }
2908
2909 gboolean
2910 mono_arm_thumb_supported (void)
2911 {
2912         return thumb_supported;
2913 }
2914
2915 /*
2916  * emit_load_volatile_arguments:
2917  *
2918  *  Load volatile arguments from the stack to the original input registers.
2919  * Required before a tail call.
2920  */
2921 static guint8*
2922 emit_load_volatile_arguments (MonoCompile *cfg, guint8 *code)
2923 {
2924         MonoMethod *method = cfg->method;
2925         MonoMethodSignature *sig;
2926         MonoInst *inst;
2927         CallInfo *cinfo;
2928         guint32 i, pos;
2929
2930         /* FIXME: Generate intermediate code instead */
2931
2932         sig = mono_method_signature (method);
2933
2934         /* This is the opposite of the code in emit_prolog */
2935
2936         pos = 0;
2937
2938         cinfo = get_call_info (NULL, sig, sig->pinvoke);
2939
2940         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2941                 ArgInfo *ainfo = &cinfo->ret;
2942                 inst = cfg->vret_addr;
2943                 g_assert (arm_is_imm12 (inst->inst_offset));
2944                 ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2945         }
2946         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2947                 ArgInfo *ainfo = cinfo->args + i;
2948                 inst = cfg->args [pos];
2949                 
2950                 if (cfg->verbose_level > 2)
2951                         g_print ("Loading argument %d (type: %d)\n", i, ainfo->storage);
2952                 if (inst->opcode == OP_REGVAR) {
2953                         if (ainfo->storage == RegTypeGeneral)
2954                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
2955                         else if (ainfo->storage == RegTypeFP) {
2956                                 g_assert_not_reached ();
2957                         } else if (ainfo->storage == RegTypeBase) {
2958                                 // FIXME:
2959                                 NOT_IMPLEMENTED;
2960                                 /*
2961                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
2962                                         ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
2963                                 } else {
2964                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2965                                         ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
2966                                 }
2967                                 */
2968                         } else
2969                                 g_assert_not_reached ();
2970                 } else {
2971                         if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair) {
2972                                 switch (ainfo->size) {
2973                                 case 1:
2974                                 case 2:
2975                                         // FIXME:
2976                                         NOT_IMPLEMENTED;
2977                                         break;
2978                                 case 8:
2979                                         g_assert (arm_is_imm12 (inst->inst_offset));
2980                                         ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2981                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
2982                                         ARM_LDR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2983                                         break;
2984                                 default:
2985                                         if (arm_is_imm12 (inst->inst_offset)) {
2986                                                 ARM_LDR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2987                                         } else {
2988                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2989                                                 ARM_LDR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
2990                                         }
2991                                         break;
2992                                 }
2993                         } else if (ainfo->storage == RegTypeBaseGen) {
2994                                 // FIXME:
2995                                 NOT_IMPLEMENTED;
2996                         } else if (ainfo->storage == RegTypeBase) {
2997                                 /* Nothing to do */
2998                         } else if (ainfo->storage == RegTypeFP) {
2999                                 g_assert_not_reached ();
3000                         } else if (ainfo->storage == RegTypeStructByVal) {
3001                                 int doffset = inst->inst_offset;
3002                                 int soffset = 0;
3003                                 int cur_reg;
3004                                 int size = 0;
3005                                 if (mono_class_from_mono_type (inst->inst_vtype))
3006                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
3007                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
3008                                         if (arm_is_imm12 (doffset)) {
3009                                                 ARM_LDR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
3010                                         } else {
3011                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
3012                                                 ARM_LDR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
3013                                         }
3014                                         soffset += sizeof (gpointer);
3015                                         doffset += sizeof (gpointer);
3016                                 }
3017                                 if (ainfo->vtsize)
3018                                         // FIXME:
3019                                         NOT_IMPLEMENTED;
3020                         } else if (ainfo->storage == RegTypeStructByAddr) {
3021                         } else {
3022                                 // FIXME:
3023                                 NOT_IMPLEMENTED;
3024                         }
3025                 }
3026                 pos ++;
3027         }
3028
3029         g_free (cinfo);
3030
3031         return code;
3032 }
3033
3034 #ifndef DISABLE_JIT
3035
3036 void
3037 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
3038 {
3039         MonoInst *ins;
3040         MonoCallInst *call;
3041         guint offset;
3042         guint8 *code = cfg->native_code + cfg->code_len;
3043         MonoInst *last_ins = NULL;
3044         guint last_offset = 0;
3045         int max_len, cpos;
3046         int imm8, rot_amount;
3047
3048         /* we don't align basic blocks of loops on arm */
3049
3050         if (cfg->verbose_level > 2)
3051                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
3052
3053         cpos = bb->max_offset;
3054
3055         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
3056                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
3057                 //g_assert (!mono_compile_aot);
3058                 //cpos += 6;
3059                 //if (bb->cil_code)
3060                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
3061                 /* this is not thread save, but good enough */
3062                 /* fixme: howto handle overflows? */
3063                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
3064         }
3065
3066     if (mono_break_at_bb_method && mono_method_desc_full_match (mono_break_at_bb_method, cfg->method) && bb->block_num == mono_break_at_bb_bb_num) {
3067                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3068                                                          (gpointer)"mono_break");
3069                 code = emit_call_seq (cfg, code);
3070         }
3071
3072         MONO_BB_FOR_EACH_INS (bb, ins) {
3073                 offset = code - cfg->native_code;
3074
3075                 max_len = ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
3076
3077                 if (offset > (cfg->code_size - max_len - 16)) {
3078                         cfg->code_size *= 2;
3079                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3080                         code = cfg->native_code + offset;
3081                 }
3082         //      if (ins->cil_code)
3083         //              g_print ("cil code\n");
3084                 mono_debug_record_line_number (cfg, ins, offset);
3085
3086                 switch (ins->opcode) {
3087                 case OP_MEMORY_BARRIER:
3088                         break;
3089                 case OP_TLS_GET:
3090 #ifdef HAVE_AEABI_READ_TP
3091                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3092                                                                  (gpointer)"__aeabi_read_tp");
3093                         code = emit_call_seq (cfg, code);
3094
3095                         ARM_LDR_IMM (code, ins->dreg, ARMREG_R0, ins->inst_offset);
3096 #else
3097                         g_assert_not_reached ();
3098 #endif
3099                         break;
3100                 /*case OP_BIGMUL:
3101                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
3102                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
3103                         break;
3104                 case OP_BIGMUL_UN:
3105                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
3106                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
3107                         break;*/
3108                 case OP_STOREI1_MEMBASE_IMM:
3109                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFF);
3110                         g_assert (arm_is_imm12 (ins->inst_offset));
3111                         ARM_STRB_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3112                         break;
3113                 case OP_STOREI2_MEMBASE_IMM:
3114                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFFFF);
3115                         g_assert (arm_is_imm8 (ins->inst_offset));
3116                         ARM_STRH_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3117                         break;
3118                 case OP_STORE_MEMBASE_IMM:
3119                 case OP_STOREI4_MEMBASE_IMM:
3120                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm);
3121                         g_assert (arm_is_imm12 (ins->inst_offset));
3122                         ARM_STR_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
3123                         break;
3124                 case OP_STOREI1_MEMBASE_REG:
3125                         g_assert (arm_is_imm12 (ins->inst_offset));
3126                         ARM_STRB_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3127                         break;
3128                 case OP_STOREI2_MEMBASE_REG:
3129                         g_assert (arm_is_imm8 (ins->inst_offset));
3130                         ARM_STRH_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3131                         break;
3132                 case OP_STORE_MEMBASE_REG:
3133                 case OP_STOREI4_MEMBASE_REG:
3134                         /* this case is special, since it happens for spill code after lowering has been called */
3135                         if (arm_is_imm12 (ins->inst_offset)) {
3136                                 ARM_STR_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3137                         } else {
3138                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
3139                                 ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
3140                         }
3141                         break;
3142                 case OP_STOREI1_MEMINDEX:
3143                         ARM_STRB_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3144                         break;
3145                 case OP_STOREI2_MEMINDEX:
3146                         ARM_STRH_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3147                         break;
3148                 case OP_STORE_MEMINDEX:
3149                 case OP_STOREI4_MEMINDEX:
3150                         ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
3151                         break;
3152                 case OP_LOADU4_MEM:
3153                         g_assert_not_reached ();
3154                         break;
3155                 case OP_LOAD_MEMINDEX:
3156                 case OP_LOADI4_MEMINDEX:
3157                 case OP_LOADU4_MEMINDEX:
3158                         ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3159                         break;
3160                 case OP_LOADI1_MEMINDEX:
3161                         ARM_LDRSB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3162                         break;
3163                 case OP_LOADU1_MEMINDEX:
3164                         ARM_LDRB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3165                         break;
3166                 case OP_LOADI2_MEMINDEX:
3167                         ARM_LDRSH_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3168                         break;
3169                 case OP_LOADU2_MEMINDEX:
3170                         ARM_LDRH_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
3171                         break;
3172                 case OP_LOAD_MEMBASE:
3173                 case OP_LOADI4_MEMBASE:
3174                 case OP_LOADU4_MEMBASE:
3175                         /* this case is special, since it happens for spill code after lowering has been called */
3176                         if (arm_is_imm12 (ins->inst_offset)) {
3177                                 ARM_LDR_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3178                         } else {
3179                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
3180                                 ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
3181                         }
3182                         break;
3183                 case OP_LOADI1_MEMBASE:
3184                         g_assert (arm_is_imm8 (ins->inst_offset));
3185                         ARM_LDRSB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3186                         break;
3187                 case OP_LOADU1_MEMBASE:
3188                         g_assert (arm_is_imm12 (ins->inst_offset));
3189                         ARM_LDRB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3190                         break;
3191                 case OP_LOADU2_MEMBASE:
3192                         g_assert (arm_is_imm8 (ins->inst_offset));
3193                         ARM_LDRH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3194                         break;
3195                 case OP_LOADI2_MEMBASE:
3196                         g_assert (arm_is_imm8 (ins->inst_offset));
3197                         ARM_LDRSH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3198                         break;
3199                 case OP_ICONV_TO_I1:
3200                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 24);
3201                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 24);
3202                         break;
3203                 case OP_ICONV_TO_I2:
3204                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
3205                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 16);
3206                         break;
3207                 case OP_ICONV_TO_U1:
3208                         ARM_AND_REG_IMM8 (code, ins->dreg, ins->sreg1, 0xff);
3209                         break;
3210                 case OP_ICONV_TO_U2:
3211                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
3212                         ARM_SHR_IMM (code, ins->dreg, ins->dreg, 16);
3213                         break;
3214                 case OP_COMPARE:
3215                 case OP_ICOMPARE:
3216                         ARM_CMP_REG_REG (code, ins->sreg1, ins->sreg2);
3217                         break;
3218                 case OP_COMPARE_IMM:
3219                 case OP_ICOMPARE_IMM:
3220                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3221                         g_assert (imm8 >= 0);
3222                         ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount);
3223                         break;
3224                 case OP_BREAK:
3225                         /*
3226                          * gdb does not like encountering the hw breakpoint ins in the debugged code. 
3227                          * So instead of emitting a trap, we emit a call a C function and place a 
3228                          * breakpoint there.
3229                          */
3230                         //*(int*)code = 0xef9f0001;
3231                         //code += 4;
3232                         //ARM_DBRK (code);
3233                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3234                                                                  (gpointer)"mono_break");
3235                         code = emit_call_seq (cfg, code);
3236                         break;
3237                 case OP_RELAXED_NOP:
3238                         ARM_NOP (code);
3239                         break;
3240                 case OP_NOP:
3241                 case OP_DUMMY_USE:
3242                 case OP_DUMMY_STORE:
3243                 case OP_NOT_REACHED:
3244                 case OP_NOT_NULL:
3245                         break;
3246                 case OP_SEQ_POINT: {
3247                         int i;
3248                         MonoInst *info_var = cfg->arch.seq_point_info_var;
3249                         MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
3250                         MonoInst *var;
3251                         int dreg = ARMREG_LR;
3252
3253                         /*
3254                          * For AOT, we use one got slot per method, which will point to a
3255                          * SeqPointInfo structure, containing all the information required
3256                          * by the code below.
3257                          */
3258                         if (cfg->compile_aot) {
3259                                 g_assert (info_var);
3260                                 g_assert (info_var->opcode == OP_REGOFFSET);
3261                                 g_assert (arm_is_imm12 (info_var->inst_offset));
3262                         }
3263
3264                         /* 
3265                          * Read from the single stepping trigger page. This will cause a
3266                          * SIGSEGV when single stepping is enabled.
3267                          * We do this _before_ the breakpoint, so single stepping after
3268                          * a breakpoint is hit will step to the next IL offset.
3269                          */
3270                         g_assert (((guint64)(gsize)ss_trigger_page >> 32) == 0);
3271
3272                         if (ins->flags & MONO_INST_SINGLE_STEP_LOC) {
3273                                 if (cfg->compile_aot) {
3274                                         /* Load the trigger page addr from the variable initialized in the prolog */
3275                                         var = ss_trigger_page_var;
3276                                         g_assert (var);
3277                                         g_assert (var->opcode == OP_REGOFFSET);
3278                                         g_assert (arm_is_imm12 (var->inst_offset));
3279                                         ARM_LDR_IMM (code, dreg, var->inst_basereg, var->inst_offset);
3280                                 } else {
3281                                         ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
3282                                         ARM_B (code, 0);
3283                                         *(int*)code = (int)ss_trigger_page;
3284                                         code += 4;
3285                                 }
3286                                 ARM_LDR_IMM (code, dreg, dreg, 0);
3287                         }
3288
3289                         mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
3290
3291                         if (cfg->compile_aot) {
3292                                 guint32 offset = code - cfg->native_code;
3293                                 guint32 val;
3294
3295                                 ARM_LDR_IMM (code, dreg, info_var->inst_basereg, info_var->inst_offset);
3296                                 /* Add the offset */
3297                                 val = ((offset / 4) * sizeof (guint8*)) + G_STRUCT_OFFSET (SeqPointInfo, bp_addrs);
3298                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF), 0);
3299                                 /* 
3300                                  * Have to emit nops to keep the difference between the offset
3301                                  * stored in seq_points and breakpoint instruction constant,
3302                                  * mono_arch_get_ip_for_breakpoint () depends on this.
3303                                  */
3304                                 if (val & 0xFF00)
3305                                         ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
3306                                 else
3307                                         ARM_NOP (code);
3308                                 if (val & 0xFF0000)
3309                                         ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
3310                                 else
3311                                         ARM_NOP (code);
3312                                 g_assert (!(val & 0xFF000000));
3313                                 /* Load the info->bp_addrs [offset], which is either 0 or the address of a trigger page */
3314                                 ARM_LDR_IMM (code, dreg, dreg, 0);
3315
3316                                 /* What is faster, a branch or a load ? */
3317                                 ARM_CMP_REG_IMM (code, dreg, 0, 0);
3318                                 /* The breakpoint instruction */
3319                                 ARM_LDR_IMM_COND (code, dreg, dreg, 0, ARMCOND_NE);
3320                         } else {
3321                                 /* 
3322                                  * A placeholder for a possible breakpoint inserted by
3323                                  * mono_arch_set_breakpoint ().
3324                                  */
3325                                 for (i = 0; i < 4; ++i)
3326                                         ARM_NOP (code);
3327                         }
3328                         break;
3329                 }
3330                 case OP_ADDCC:
3331                 case OP_IADDCC:
3332                         ARM_ADDS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3333                         break;
3334                 case OP_IADD:
3335                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3336                         break;
3337                 case OP_ADC:
3338                 case OP_IADC:
3339                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3340                         break;
3341                 case OP_ADDCC_IMM:
3342                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3343                         g_assert (imm8 >= 0);
3344                         ARM_ADDS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3345                         break;
3346                 case OP_ADD_IMM:
3347                 case OP_IADD_IMM:
3348                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3349                         g_assert (imm8 >= 0);
3350                         ARM_ADD_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3351                         break;
3352                 case OP_ADC_IMM:
3353                 case OP_IADC_IMM:
3354                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3355                         g_assert (imm8 >= 0);
3356                         ARM_ADCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3357                         break;
3358                 case OP_IADD_OVF:
3359                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3360                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3361                         break;
3362                 case OP_IADD_OVF_UN:
3363                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3364                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3365                         break;
3366                 case OP_ISUB_OVF:
3367                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3368                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3369                         break;
3370                 case OP_ISUB_OVF_UN:
3371                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3372                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3373                         break;
3374                 case OP_ADD_OVF_CARRY:
3375                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3376                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3377                         break;
3378                 case OP_ADD_OVF_UN_CARRY:
3379                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3380                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3381                         break;
3382                 case OP_SUB_OVF_CARRY:
3383                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3384                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
3385                         break;
3386                 case OP_SUB_OVF_UN_CARRY:
3387                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3388                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
3389                         break;
3390                 case OP_SUBCC:
3391                 case OP_ISUBCC:
3392                         ARM_SUBS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3393                         break;
3394                 case OP_SUBCC_IMM:
3395                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3396                         g_assert (imm8 >= 0);
3397                         ARM_SUBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3398                         break;
3399                 case OP_ISUB:
3400                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3401                         break;
3402                 case OP_SBB:
3403                 case OP_ISBB:
3404                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3405                         break;
3406                 case OP_SUB_IMM:
3407                 case OP_ISUB_IMM:
3408                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3409                         g_assert (imm8 >= 0);
3410                         ARM_SUB_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3411                         break;
3412                 case OP_SBB_IMM:
3413                 case OP_ISBB_IMM:
3414                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3415                         g_assert (imm8 >= 0);
3416                         ARM_SBCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3417                         break;
3418                 case OP_ARM_RSBS_IMM:
3419                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3420                         g_assert (imm8 >= 0);
3421                         ARM_RSBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3422                         break;
3423                 case OP_ARM_RSC_IMM:
3424                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3425                         g_assert (imm8 >= 0);
3426                         ARM_RSC_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3427                         break;
3428                 case OP_IAND:
3429                         ARM_AND_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3430                         break;
3431                 case OP_AND_IMM:
3432                 case OP_IAND_IMM:
3433                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3434                         g_assert (imm8 >= 0);
3435                         ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3436                         break;
3437                 case OP_IDIV:
3438                 case OP_IDIV_UN:
3439                 case OP_DIV_IMM:
3440                 case OP_IREM:
3441                 case OP_IREM_UN:
3442                 case OP_REM_IMM:
3443                         /* crappy ARM arch doesn't have a DIV instruction */
3444                         g_assert_not_reached ();
3445                 case OP_IOR:
3446                         ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3447                         break;
3448                 case OP_OR_IMM:
3449                 case OP_IOR_IMM:
3450                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3451                         g_assert (imm8 >= 0);
3452                         ARM_ORR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3453                         break;
3454                 case OP_IXOR:
3455                         ARM_EOR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3456                         break;
3457                 case OP_XOR_IMM:
3458                 case OP_IXOR_IMM:
3459                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
3460                         g_assert (imm8 >= 0);
3461                         ARM_EOR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
3462                         break;
3463                 case OP_ISHL:
3464                         ARM_SHL_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3465                         break;
3466                 case OP_SHL_IMM:
3467                 case OP_ISHL_IMM:
3468                         if (ins->inst_imm)
3469                                 ARM_SHL_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3470                         else if (ins->dreg != ins->sreg1)
3471                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
3472                         break;
3473                 case OP_ISHR:
3474                         ARM_SAR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3475                         break;
3476                 case OP_SHR_IMM:
3477                 case OP_ISHR_IMM:
3478                         if (ins->inst_imm)
3479                                 ARM_SAR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3480                         else if (ins->dreg != ins->sreg1)
3481                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
3482                         break;
3483                 case OP_SHR_UN_IMM:
3484                 case OP_ISHR_UN_IMM:
3485                         if (ins->inst_imm)
3486                                 ARM_SHR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
3487                         else if (ins->dreg != ins->sreg1)
3488                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
3489                         break;
3490                 case OP_ISHR_UN:
3491                         ARM_SHR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3492                         break;
3493                 case OP_INOT:
3494                         ARM_MVN_REG_REG (code, ins->dreg, ins->sreg1);
3495                         break;
3496                 case OP_INEG:
3497                         ARM_RSB_REG_IMM8 (code, ins->dreg, ins->sreg1, 0);
3498                         break;
3499                 case OP_IMUL:
3500                         if (ins->dreg == ins->sreg2)
3501                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3502                         else
3503                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg2, ins->sreg1);
3504                         break;
3505                 case OP_MUL_IMM:
3506                         g_assert_not_reached ();
3507                         break;
3508                 case OP_IMUL_OVF:
3509                         /* FIXME: handle ovf/ sreg2 != dreg */
3510                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3511                         /* FIXME: MUL doesn't set the C/O flags on ARM */
3512                         break;
3513                 case OP_IMUL_OVF_UN:
3514                         /* FIXME: handle ovf/ sreg2 != dreg */
3515                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
3516                         /* FIXME: MUL doesn't set the C/O flags on ARM */
3517                         break;
3518                 case OP_ICONST:
3519                         code = mono_arm_emit_load_imm (code, ins->dreg, ins->inst_c0);
3520                         break;
3521                 case OP_AOTCONST:
3522                         /* Load the GOT offset */
3523                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
3524                         ARM_LDR_IMM (code, ins->dreg, ARMREG_PC, 0);
3525                         ARM_B (code, 0);
3526                         *(gpointer*)code = NULL;
3527                         code += 4;
3528                         /* Load the value from the GOT */
3529                         ARM_LDR_REG_REG (code, ins->dreg, ARMREG_PC, ins->dreg);
3530                         break;
3531                 case OP_ICONV_TO_I4:
3532                 case OP_ICONV_TO_U4:
3533                 case OP_MOVE:
3534                         if (ins->dreg != ins->sreg1)
3535                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
3536                         break;
3537                 case OP_SETLRET: {
3538                         int saved = ins->sreg2;
3539                         if (ins->sreg2 == ARM_LSW_REG) {
3540                                 ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg2);
3541                                 saved = ARMREG_LR;
3542                         }
3543                         if (ins->sreg1 != ARM_LSW_REG)
3544                                 ARM_MOV_REG_REG (code, ARM_LSW_REG, ins->sreg1);
3545                         if (saved != ARM_MSW_REG)
3546                                 ARM_MOV_REG_REG (code, ARM_MSW_REG, saved);
3547                         break;
3548                 }
3549                 case OP_FMOVE:
3550 #ifdef ARM_FPU_FPA
3551                         ARM_MVFD (code, ins->dreg, ins->sreg1);
3552 #elif defined(ARM_FPU_VFP)
3553                         ARM_CPYD (code, ins->dreg, ins->sreg1);
3554 #endif
3555                         break;
3556                 case OP_FCONV_TO_R4:
3557 #ifdef ARM_FPU_FPA
3558                         ARM_MVFS (code, ins->dreg, ins->sreg1);
3559 #elif defined(ARM_FPU_VFP)
3560                         ARM_CVTD (code, ins->dreg, ins->sreg1);
3561                         ARM_CVTS (code, ins->dreg, ins->dreg);
3562 #endif
3563                         break;
3564                 case OP_JMP:
3565                         /*
3566                          * Keep in sync with mono_arch_emit_epilog
3567                          */
3568                         g_assert (!cfg->method->save_lmf);
3569
3570                         code = emit_load_volatile_arguments (cfg, code);
3571
3572                         code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
3573                         ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP)) | ((1 << ARMREG_LR)));
3574                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
3575                         if (cfg->compile_aot) {
3576                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
3577                                 ARM_B (code, 0);
3578                                 *(gpointer*)code = NULL;
3579                                 code += 4;
3580                                 ARM_LDR_REG_REG (code, ARMREG_PC, ARMREG_PC, ARMREG_IP);
3581                         } else {
3582                                 ARM_B (code, 0);
3583                         }
3584                         break;
3585                 case OP_CHECK_THIS:
3586                         /* ensure ins->sreg1 is not NULL */
3587                         ARM_LDR_IMM (code, ARMREG_LR, ins->sreg1, 0);
3588                         break;
3589                 case OP_ARGLIST: {
3590                         g_assert (cfg->sig_cookie < 128);
3591                         ARM_LDR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie);
3592                         ARM_STR_IMM (code, ARMREG_IP, ins->sreg1, 0);
3593                         break;
3594                 }
3595                 case OP_FCALL:
3596                 case OP_LCALL:
3597                 case OP_VCALL:
3598                 case OP_VCALL2:
3599                 case OP_VOIDCALL:
3600                 case OP_CALL:
3601                         call = (MonoCallInst*)ins;
3602                         if (ins->flags & MONO_INST_HAS_METHOD)
3603                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
3604                         else
3605                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
3606                         code = emit_call_seq (cfg, code);
3607                         code = emit_move_return_value (cfg, ins, code);
3608                         break;
3609                 case OP_FCALL_REG:
3610                 case OP_LCALL_REG:
3611                 case OP_VCALL_REG:
3612                 case OP_VCALL2_REG:
3613                 case OP_VOIDCALL_REG:
3614                 case OP_CALL_REG:
3615                         code = emit_call_reg (code, ins->sreg1);
3616                         code = emit_move_return_value (cfg, ins, code);
3617                         break;
3618                 case OP_FCALL_MEMBASE:
3619                 case OP_LCALL_MEMBASE:
3620                 case OP_VCALL_MEMBASE:
3621                 case OP_VCALL2_MEMBASE:
3622                 case OP_VOIDCALL_MEMBASE:
3623                 case OP_CALL_MEMBASE:
3624                         g_assert (arm_is_imm12 (ins->inst_offset));
3625                         g_assert (ins->sreg1 != ARMREG_LR);
3626                         call = (MonoCallInst*)ins;
3627                         if (call->method->klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
3628                                 ARM_ADD_REG_IMM8 (code, ARMREG_LR, ARMREG_PC, 4);
3629                                 ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
3630                                 /* 
3631                                  * We can't embed the method in the code stream in PIC code, or
3632                                  * in gshared code.
3633                                  * Instead, we put it in V5 in code emitted by 
3634                                  * mono_arch_emit_imt_argument (), and embed NULL here to 
3635                                  * signal the IMT thunk that the value is in V5.
3636                                  */
3637                                 if (call->dynamic_imt_arg)
3638                                         *((gpointer*)code) = NULL;
3639                                 else
3640                                         *((gpointer*)code) = (gpointer)call->method;
3641                                 code += 4;
3642                         } else {
3643                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
3644                                 ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
3645                         }
3646                         code = emit_move_return_value (cfg, ins, code);
3647                         break;
3648                 case OP_LOCALLOC: {
3649                         /* keep alignment */
3650                         int alloca_waste = cfg->param_area;
3651                         alloca_waste += 7;
3652                         alloca_waste &= ~7;
3653                         /* round the size to 8 bytes */
3654                         ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
3655                         ARM_BIC_REG_IMM8 (code, ins->dreg, ins->dreg, 7);
3656                         if (alloca_waste)
3657                                 ARM_ADD_REG_IMM8 (code, ins->dreg, ins->dreg, alloca_waste);
3658                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ins->dreg);
3659                         /* memzero the area: dreg holds the size, sp is the pointer */
3660                         if (ins->flags & MONO_INST_INIT) {
3661                                 guint8 *start_loop, *branch_to_cond;
3662                                 ARM_MOV_REG_IMM8 (code, ARMREG_LR, 0);
3663                                 branch_to_cond = code;
3664                                 ARM_B (code, 0);
3665                                 start_loop = code;
3666                                 ARM_STR_REG_REG (code, ARMREG_LR, ARMREG_SP, ins->dreg);
3667                                 arm_patch (branch_to_cond, code);
3668                                 /* decrement by 4 and set flags */
3669                                 ARM_SUBS_REG_IMM8 (code, ins->dreg, ins->dreg, 4);
3670                                 ARM_B_COND (code, ARMCOND_GE, 0);
3671                                 arm_patch (code - 4, start_loop);
3672                         }
3673                         ARM_ADD_REG_IMM8 (code, ins->dreg, ARMREG_SP, alloca_waste);
3674                         break;
3675                 }
3676                 case OP_DYN_CALL: {
3677                         int i;
3678                         MonoInst *var = cfg->dyn_call_var;
3679
3680                         g_assert (var->opcode == OP_REGOFFSET);
3681                         g_assert (arm_is_imm12 (var->inst_offset));
3682
3683                         /* lr = args buffer filled by mono_arch_get_dyn_call_args () */
3684                         ARM_MOV_REG_REG( code, ARMREG_LR, ins->sreg1);
3685                         /* ip = ftn */
3686                         ARM_MOV_REG_REG( code, ARMREG_IP, ins->sreg2);
3687
3688                         /* Save args buffer */
3689                         ARM_STR_IMM (code, ARMREG_LR, var->inst_basereg, var->inst_offset);
3690
3691                         /* Set stack slots using R0 as scratch reg */
3692                         /* MONO_ARCH_DYN_CALL_PARAM_AREA gives the size of stack space available */
3693                         for (i = 0; i < DYN_CALL_STACK_ARGS; ++i) {
3694                                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, (PARAM_REGS + i) * sizeof (gpointer));
3695                                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_SP, i * sizeof (gpointer));
3696                         }
3697
3698                         /* Set argument registers */
3699                         for (i = 0; i < PARAM_REGS; ++i)
3700                                 ARM_LDR_IMM (code, i, ARMREG_LR, i * sizeof (gpointer));
3701
3702                         /* Make the call */
3703                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
3704                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
3705
3706                         /* Save result */
3707                         ARM_LDR_IMM (code, ARMREG_IP, var->inst_basereg, var->inst_offset);
3708                         ARM_STR_IMM (code, ARMREG_R0, ARMREG_IP, G_STRUCT_OFFSET (DynCallArgs, res)); 
3709                         ARM_STR_IMM (code, ARMREG_R1, ARMREG_IP, G_STRUCT_OFFSET (DynCallArgs, res2)); 
3710                         break;
3711                 }
3712                 case OP_THROW: {
3713                         if (ins->sreg1 != ARMREG_R0)
3714                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
3715                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3716                                              (gpointer)"mono_arch_throw_exception");
3717                         code = emit_call_seq (cfg, code);
3718                         break;
3719                 }
3720                 case OP_RETHROW: {
3721                         if (ins->sreg1 != ARMREG_R0)
3722                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
3723                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
3724                                              (gpointer)"mono_arch_rethrow_exception");
3725                         code = emit_call_seq (cfg, code);
3726                         break;
3727                 }
3728                 case OP_START_HANDLER: {
3729                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3730
3731                         if (arm_is_imm12 (spvar->inst_offset)) {
3732                                 ARM_STR_IMM (code, ARMREG_LR, spvar->inst_basereg, spvar->inst_offset);
3733                         } else {
3734                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
3735                                 ARM_STR_REG_REG (code, ARMREG_LR, spvar->inst_basereg, ARMREG_IP);
3736                         }
3737                         break;
3738                 }
3739                 case OP_ENDFILTER: {
3740                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3741
3742                         if (ins->sreg1 != ARMREG_R0)
3743                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
3744                         if (arm_is_imm12 (spvar->inst_offset)) {
3745                                 ARM_LDR_IMM (code, ARMREG_IP, spvar->inst_basereg, spvar->inst_offset);
3746                         } else {
3747                                 g_assert (ARMREG_IP != spvar->inst_basereg);
3748                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
3749                                 ARM_LDR_REG_REG (code, ARMREG_IP, spvar->inst_basereg, ARMREG_IP);
3750                         }
3751                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
3752                         break;
3753                 }
3754                 case OP_ENDFINALLY: {
3755                         MonoInst *spvar = mono_find_spvar_for_region (cfg, bb->region);
3756
3757                         if (arm_is_imm12 (spvar->inst_offset)) {
3758                                 ARM_LDR_IMM (code, ARMREG_IP, spvar->inst_basereg, spvar->inst_offset);
3759                         } else {
3760                                 g_assert (ARMREG_IP != spvar->inst_basereg);
3761                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, spvar->inst_offset);
3762                                 ARM_LDR_REG_REG (code, ARMREG_IP, spvar->inst_basereg, ARMREG_IP);
3763                         }
3764                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
3765                         break;
3766                 }
3767                 case OP_CALL_HANDLER: 
3768                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3769                         ARM_BL (code, 0);
3770                         break;
3771                 case OP_LABEL:
3772                         ins->inst_c0 = code - cfg->native_code;
3773                         break;
3774                 case OP_BR:
3775                         /*if (ins->inst_target_bb->native_offset) {
3776                                 ARM_B (code, 0);
3777                                 //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
3778                         } else*/ {
3779                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
3780                                 ARM_B (code, 0);
3781                         } 
3782                         break;
3783                 case OP_BR_REG:
3784                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
3785                         break;
3786                 case OP_SWITCH:
3787                         /* 
3788                          * In the normal case we have:
3789                          *      ldr pc, [pc, ins->sreg1 << 2]
3790                          *      nop
3791                          * If aot, we have:
3792                          *      ldr lr, [pc, ins->sreg1 << 2]
3793                          *      add pc, pc, lr
3794                          * After follows the data.
3795                          * FIXME: add aot support.
3796                          */
3797                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_SWITCH, ins->inst_p0);
3798                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
3799                         if (offset > (cfg->code_size - max_len - 16)) {
3800                                 cfg->code_size += max_len;
3801                                 cfg->code_size *= 2;
3802                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3803                                 code = cfg->native_code + offset;
3804                         }
3805                         ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_PC, ins->sreg1, ARMSHIFT_LSL, 2);
3806                         ARM_NOP (code);
3807                         code += 4 * GPOINTER_TO_INT (ins->klass);
3808                         break;
3809                 case OP_CEQ:
3810                 case OP_ICEQ:
3811                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
3812                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
3813                         break;
3814                 case OP_CLT:
3815                 case OP_ICLT:
3816                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3817                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LT);
3818                         break;
3819                 case OP_CLT_UN:
3820                 case OP_ICLT_UN:
3821                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3822                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LO);
3823                         break;
3824                 case OP_CGT:
3825                 case OP_ICGT:
3826                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3827                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_GT);
3828                         break;
3829                 case OP_CGT_UN:
3830                 case OP_ICGT_UN:
3831                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
3832                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_HI);
3833                         break;
3834                 case OP_COND_EXC_EQ:
3835                 case OP_COND_EXC_NE_UN:
3836                 case OP_COND_EXC_LT:
3837                 case OP_COND_EXC_LT_UN:
3838                 case OP_COND_EXC_GT:
3839                 case OP_COND_EXC_GT_UN:
3840                 case OP_COND_EXC_GE:
3841                 case OP_COND_EXC_GE_UN:
3842                 case OP_COND_EXC_LE:
3843                 case OP_COND_EXC_LE_UN:
3844                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
3845                         break;
3846                 case OP_COND_EXC_IEQ:
3847                 case OP_COND_EXC_INE_UN:
3848                 case OP_COND_EXC_ILT:
3849                 case OP_COND_EXC_ILT_UN:
3850                 case OP_COND_EXC_IGT:
3851                 case OP_COND_EXC_IGT_UN:
3852                 case OP_COND_EXC_IGE:
3853                 case OP_COND_EXC_IGE_UN:
3854                 case OP_COND_EXC_ILE:
3855                 case OP_COND_EXC_ILE_UN:
3856                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_IEQ, ins->inst_p1);
3857                         break;
3858                 case OP_COND_EXC_C:
3859                 case OP_COND_EXC_IC:
3860                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_CS, ins->inst_p1);
3861                         break;
3862                 case OP_COND_EXC_OV:
3863                 case OP_COND_EXC_IOV:
3864                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, ins->inst_p1);
3865                         break;
3866                 case OP_COND_EXC_NC:
3867                 case OP_COND_EXC_INC:
3868                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_CC, ins->inst_p1);
3869                         break;
3870                 case OP_COND_EXC_NO:
3871                 case OP_COND_EXC_INO:
3872                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VC, ins->inst_p1);
3873                         break;
3874                 case OP_IBEQ:
3875                 case OP_IBNE_UN:
3876                 case OP_IBLT:
3877                 case OP_IBLT_UN:
3878                 case OP_IBGT:
3879                 case OP_IBGT_UN:
3880                 case OP_IBGE:
3881                 case OP_IBGE_UN:
3882                 case OP_IBLE:
3883                 case OP_IBLE_UN:
3884                         EMIT_COND_BRANCH (ins, ins->opcode - OP_IBEQ);
3885                         break;
3886
3887                 /* floating point opcodes */
3888 #ifdef ARM_FPU_FPA
3889                 case OP_R8CONST:
3890                         if (cfg->compile_aot) {
3891                                 ARM_LDFD (code, ins->dreg, ARMREG_PC, 0);
3892                                 ARM_B (code, 1);
3893                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
3894                                 code += 4;
3895                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[1];
3896                                 code += 4;
3897                         } else {
3898                                 /* FIXME: we can optimize the imm load by dealing with part of 
3899                                  * the displacement in LDFD (aligning to 512).
3900                                  */
3901                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
3902                                 ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
3903                         }
3904                         break;
3905                 case OP_R4CONST:
3906                         if (cfg->compile_aot) {
3907                                 ARM_LDFS (code, ins->dreg, ARMREG_PC, 0);
3908                                 ARM_B (code, 0);
3909                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
3910                                 code += 4;
3911                         } else {
3912                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
3913                                 ARM_LDFS (code, ins->dreg, ARMREG_LR, 0);
3914                         }
3915                         break;
3916                 case OP_STORER8_MEMBASE_REG:
3917                         /* This is generated by the local regalloc pass which runs after the lowering pass */
3918                         if (!arm_is_fpimm8 (ins->inst_offset)) {
3919                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
3920                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_destbasereg);
3921                                 ARM_STFD (code, ins->sreg1, ARMREG_LR, 0);
3922                         } else {
3923                                 ARM_STFD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3924                         }
3925                         break;
3926                 case OP_LOADR8_MEMBASE:
3927                         /* This is generated by the local regalloc pass which runs after the lowering pass */
3928                         if (!arm_is_fpimm8 (ins->inst_offset)) {
3929                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
3930                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_basereg);
3931                                 ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
3932                         } else {
3933                                 ARM_LDFD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3934                         }
3935                         break;
3936                 case OP_STORER4_MEMBASE_REG:
3937                         g_assert (arm_is_fpimm8 (ins->inst_offset));
3938                         ARM_STFS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
3939                         break;
3940                 case OP_LOADR4_MEMBASE:
3941                         g_assert (arm_is_fpimm8 (ins->inst_offset));
3942                         ARM_LDFS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
3943                         break;
3944                 case OP_ICONV_TO_R_UN: {
3945                         int tmpreg;
3946                         tmpreg = ins->dreg == 0? 1: 0;
3947                         ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
3948                         ARM_FLTD (code, ins->dreg, ins->sreg1);
3949                         ARM_B_COND (code, ARMCOND_GE, 8);
3950                         /* save the temp register */
3951                         ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
3952                         ARM_STFD (code, tmpreg, ARMREG_SP, 0);
3953                         ARM_LDFD (code, tmpreg, ARMREG_PC, 12);
3954                         ARM_FPA_ADFD (code, ins->dreg, ins->dreg, tmpreg);
3955                         ARM_LDFD (code, tmpreg, ARMREG_SP, 0);
3956                         ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
3957                         /* skip the constant pool */
3958                         ARM_B (code, 8);
3959                         code += 4;
3960                         *(int*)code = 0x41f00000;
3961                         code += 4;
3962                         *(int*)code = 0;
3963                         code += 4;
3964                         /* FIXME: adjust:
3965                          * ldfltd  ftemp, [pc, #8] 0x41f00000 0x00000000
3966                          * adfltd  fdest, fdest, ftemp
3967                          */
3968                         break;
3969                 }
3970                 case OP_ICONV_TO_R4:
3971                         ARM_FLTS (code, ins->dreg, ins->sreg1);
3972                         break;
3973                 case OP_ICONV_TO_R8:
3974                         ARM_FLTD (code, ins->dreg, ins->sreg1);
3975                         break;
3976
3977 #elif defined(ARM_FPU_VFP)
3978
3979                 case OP_R8CONST:
3980                         if (cfg->compile_aot) {
3981                                 ARM_FLDD (code, ins->dreg, ARMREG_PC, 0);
3982                                 ARM_B (code, 1);
3983                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
3984                                 code += 4;
3985                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[1];
3986                                 code += 4;
3987                         } else {
3988                                 /* FIXME: we can optimize the imm load by dealing with part of 
3989                                  * the displacement in LDFD (aligning to 512).
3990                                  */
3991                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
3992                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
3993                         }
3994                         break;
3995                 case OP_R4CONST:
3996                         if (cfg->compile_aot) {
3997                                 ARM_FLDS (code, ins->dreg, ARMREG_PC, 0);
3998                                 ARM_B (code, 0);
3999                                 *(guint32*)code = ((guint32*)(ins->inst_p0))[0];
4000                                 code += 4;
4001                                 ARM_CVTS (code, ins->dreg, ins->dreg);
4002                         } else {
4003                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
4004                                 ARM_FLDS (code, ins->dreg, ARMREG_LR, 0);
4005                                 ARM_CVTS (code, ins->dreg, ins->dreg);
4006                         }
4007                         break;
4008                 case OP_STORER8_MEMBASE_REG:
4009                         /* This is generated by the local regalloc pass which runs after the lowering pass */
4010                         if (!arm_is_fpimm8 (ins->inst_offset)) {
4011                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4012                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_destbasereg);
4013                                 ARM_FSTD (code, ins->sreg1, ARMREG_LR, 0);
4014                         } else {
4015                                 ARM_FSTD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
4016                         }
4017                         break;
4018                 case OP_LOADR8_MEMBASE:
4019                         /* This is generated by the local regalloc pass which runs after the lowering pass */
4020                         if (!arm_is_fpimm8 (ins->inst_offset)) {
4021                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4022                                 ARM_ADD_REG_REG (code, ARMREG_LR, ARMREG_LR, ins->inst_basereg);
4023                                 ARM_FLDD (code, ins->dreg, ARMREG_LR, 0);
4024                         } else {
4025                                 ARM_FLDD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
4026                         }
4027                         break;
4028                 case OP_STORER4_MEMBASE_REG:
4029                         g_assert (arm_is_fpimm8 (ins->inst_offset));
4030                         ARM_CVTD (code, ARM_VFP_F0, ins->sreg1);
4031                         ARM_FSTS (code, ARM_VFP_F0, ins->inst_destbasereg, ins->inst_offset);
4032                         break;
4033                 case OP_LOADR4_MEMBASE:
4034                         g_assert (arm_is_fpimm8 (ins->inst_offset));
4035                         ARM_FLDS (code, ARM_VFP_F0, ins->inst_basereg, ins->inst_offset);
4036                         ARM_CVTS (code, ins->dreg, ARM_VFP_F0);
4037                         break;
4038                 case OP_ICONV_TO_R_UN: {
4039                         g_assert_not_reached ();
4040                         break;
4041                 }
4042                 case OP_ICONV_TO_R4:
4043                         ARM_FMSR (code, ARM_VFP_F0, ins->sreg1);
4044                         ARM_FSITOS (code, ARM_VFP_F0, ARM_VFP_F0);
4045                         ARM_CVTS (code, ins->dreg, ARM_VFP_F0);
4046                         break;
4047                 case OP_ICONV_TO_R8:
4048                         ARM_FMSR (code, ARM_VFP_F0, ins->sreg1);
4049                         ARM_FSITOD (code, ins->dreg, ARM_VFP_F0);
4050                         break;
4051
4052                 case OP_SETFRET:
4053                         if (mono_method_signature (cfg->method)->ret->type == MONO_TYPE_R4) {
4054                                 ARM_CVTD (code, ARM_VFP_F0, ins->sreg1);
4055                                 ARM_FMRS (code, ARMREG_R0, ARM_VFP_F0);
4056                         } else {
4057                                 ARM_FMRRD (code, ARMREG_R0, ARMREG_R1, ins->sreg1);
4058                         }
4059                         break;
4060
4061 #endif
4062
4063                 case OP_FCONV_TO_I1:
4064                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
4065                         break;
4066                 case OP_FCONV_TO_U1:
4067                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
4068                         break;
4069                 case OP_FCONV_TO_I2:
4070                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
4071                         break;
4072                 case OP_FCONV_TO_U2:
4073                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
4074                         break;
4075                 case OP_FCONV_TO_I4:
4076                 case OP_FCONV_TO_I:
4077                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
4078                         break;
4079                 case OP_FCONV_TO_U4:
4080                 case OP_FCONV_TO_U:
4081                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
4082                         break;
4083                 case OP_FCONV_TO_I8:
4084                 case OP_FCONV_TO_U8:
4085                         g_assert_not_reached ();
4086                         /* Implemented as helper calls */
4087                         break;
4088                 case OP_LCONV_TO_R_UN:
4089                         g_assert_not_reached ();
4090                         /* Implemented as helper calls */
4091                         break;
4092                 case OP_LCONV_TO_OVF_I4_2: {
4093                         guint8 *high_bit_not_set, *valid_negative, *invalid_negative, *valid_positive;
4094                         /* 
4095                          * Valid ints: 0xffffffff:8000000 to 00000000:0x7f000000
4096                          */
4097
4098                         ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
4099                         high_bit_not_set = code;
4100                         ARM_B_COND (code, ARMCOND_GE, 0); /*branch if bit 31 of the lower part is not set*/
4101
4102                         ARM_CMN_REG_IMM8 (code, ins->sreg2, 1); /*This have the same effect as CMP reg, 0xFFFFFFFF */
4103                         valid_negative = code;
4104                         ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0xFFFFFFFF (lower part has bit 31 set) */
4105                         invalid_negative = code;
4106                         ARM_B_COND (code, ARMCOND_AL, 0);
4107                         
4108                         arm_patch (high_bit_not_set, code);
4109
4110                         ARM_CMP_REG_IMM8 (code, ins->sreg2, 0);
4111                         valid_positive = code;
4112                         ARM_B_COND (code, ARMCOND_EQ, 0); /*branch if upper part == 0 (lower part has bit 31 clear)*/
4113
4114                         arm_patch (invalid_negative, code);
4115                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_AL, "OverflowException");
4116
4117                         arm_patch (valid_negative, code);
4118                         arm_patch (valid_positive, code);
4119
4120                         if (ins->dreg != ins->sreg1)
4121                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
4122                         break;
4123                 }
4124 #ifdef ARM_FPU_FPA
4125                 case OP_FADD:
4126                         ARM_FPA_ADFD (code, ins->dreg, ins->sreg1, ins->sreg2);
4127                         break;
4128                 case OP_FSUB:
4129                         ARM_FPA_SUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
4130                         break;          
4131                 case OP_FMUL:
4132                         ARM_FPA_MUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
4133                         break;          
4134                 case OP_FDIV:
4135                         ARM_FPA_DVFD (code, ins->dreg, ins->sreg1, ins->sreg2);
4136                         break;          
4137                 case OP_FNEG:
4138                         ARM_MNFD (code, ins->dreg, ins->sreg1);
4139                         break;
4140 #elif defined(ARM_FPU_VFP)
4141                 case OP_FADD:
4142                         ARM_VFP_ADDD (code, ins->dreg, ins->sreg1, ins->sreg2);
4143                         break;
4144                 case OP_FSUB:
4145                         ARM_VFP_SUBD (code, ins->dreg, ins->sreg1, ins->sreg2);
4146                         break;          
4147                 case OP_FMUL:
4148                         ARM_VFP_MULD (code, ins->dreg, ins->sreg1, ins->sreg2);
4149                         break;          
4150                 case OP_FDIV:
4151                         ARM_VFP_DIVD (code, ins->dreg, ins->sreg1, ins->sreg2);
4152                         break;          
4153                 case OP_FNEG:
4154                         ARM_NEGD (code, ins->dreg, ins->sreg1);
4155                         break;
4156 #endif
4157                 case OP_FREM:
4158                         /* emulated */
4159                         g_assert_not_reached ();
4160                         break;
4161                 case OP_FCOMPARE:
4162 #ifdef ARM_FPU_FPA
4163                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
4164 #elif defined(ARM_FPU_VFP)
4165                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
4166                         ARM_FMSTAT (code);
4167 #endif
4168                         break;
4169                 case OP_FCEQ:
4170 #ifdef ARM_FPU_FPA
4171                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
4172 #elif defined(ARM_FPU_VFP)
4173                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
4174                         ARM_FMSTAT (code);
4175 #endif
4176                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
4177                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
4178                         break;
4179                 case OP_FCLT:
4180 #ifdef ARM_FPU_FPA
4181                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
4182 #elif defined(ARM_FPU_VFP)
4183                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
4184                         ARM_FMSTAT (code);
4185 #endif
4186                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
4187                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
4188                         break;
4189                 case OP_FCLT_UN:
4190 #ifdef ARM_FPU_FPA
4191                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
4192 #elif defined(ARM_FPU_VFP)
4193                         ARM_CMPD (code, ins->sreg1, ins->sreg2);
4194                         ARM_FMSTAT (code);
4195 #endif
4196                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
4197                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
4198                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
4199                         break;
4200                 case OP_FCGT:
4201                         /* swapped */
4202 #ifdef ARM_FPU_FPA
4203                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
4204 #elif defined(ARM_FPU_VFP)
4205                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
4206                         ARM_FMSTAT (code);
4207 #endif
4208                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
4209                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
4210                         break;
4211                 case OP_FCGT_UN:
4212                         /* swapped */
4213 #ifdef ARM_FPU_FPA
4214                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
4215 #elif defined(ARM_FPU_VFP)
4216                         ARM_CMPD (code, ins->sreg2, ins->sreg1);
4217                         ARM_FMSTAT (code);
4218 #endif
4219                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
4220                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
4221                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
4222                         break;
4223                 /* ARM FPA flags table:
4224                  * N        Less than               ARMCOND_MI
4225                  * Z        Equal                   ARMCOND_EQ
4226                  * C        Greater Than or Equal   ARMCOND_CS
4227                  * V        Unordered               ARMCOND_VS
4228                  */
4229                 case OP_FBEQ:
4230                         EMIT_COND_BRANCH (ins, OP_IBEQ - OP_IBEQ);
4231                         break;
4232                 case OP_FBNE_UN:
4233                         EMIT_COND_BRANCH (ins, OP_IBNE_UN - OP_IBEQ);
4234                         break;
4235                 case OP_FBLT:
4236                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
4237                         break;
4238                 case OP_FBLT_UN:
4239                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
4240                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
4241                         break;
4242                 case OP_FBGT:
4243                 case OP_FBGT_UN:
4244                 case OP_FBLE:
4245                 case OP_FBLE_UN:
4246                         g_assert_not_reached ();
4247                         break;
4248                 case OP_FBGE:
4249 #ifdef ARM_FPU_VFP
4250                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
4251 #else
4252                         /* FPA requires EQ even thou the docs suggests that just CS is enough */                         
4253                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_EQ);
4254                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
4255 #endif
4256                         break;
4257                 case OP_FBGE_UN:
4258                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
4259                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
4260                         break;
4261
4262                 case OP_CKFINITE: {
4263 #ifdef ARM_FPU_FPA
4264                         if (ins->dreg != ins->sreg1)
4265                                 ARM_MVFD (code, ins->dreg, ins->sreg1);
4266 #elif defined(ARM_FPU_VFP)
4267                         ARM_ABSD (code, ARM_VFP_D1, ins->sreg1);
4268                         ARM_FLDD (code, ARM_VFP_D0, ARMREG_PC, 0);
4269                         ARM_B (code, 1);
4270                         *(guint32*)code = 0xffffffff;
4271                         code += 4;
4272                         *(guint32*)code = 0x7fefffff;
4273                         code += 4;
4274                         ARM_CMPD (code, ARM_VFP_D1, ARM_VFP_D0);
4275                         ARM_FMSTAT (code);
4276                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_GT, "ArithmeticException");
4277                         ARM_CMPD (code, ins->sreg1, ins->sreg1);
4278                         ARM_FMSTAT (code);
4279                         EMIT_COND_SYSTEM_EXCEPTION_FLAGS (ARMCOND_VS, "ArithmeticException");                   
4280
4281                         ARM_CPYD (code, ins->dreg, ins->sreg1);
4282 #endif
4283                         break;
4284                 }
4285                 default:
4286                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
4287                         g_assert_not_reached ();
4288                 }
4289
4290                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
4291                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
4292                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
4293                         g_assert_not_reached ();
4294                 }
4295                
4296                 cpos += max_len;
4297
4298                 last_ins = ins;
4299                 last_offset = offset;
4300         }
4301
4302         cfg->code_len = code - cfg->native_code;
4303 }
4304
4305 #endif /* DISABLE_JIT */
4306
4307 #ifdef HAVE_AEABI_READ_TP
4308 void __aeabi_read_tp (void);
4309 #endif
4310
4311 void
4312 mono_arch_register_lowlevel_calls (void)
4313 {
4314         /* The signature doesn't matter */
4315         mono_register_jit_icall (mono_arm_throw_exception, "mono_arm_throw_exception", mono_create_icall_signature ("void"), TRUE);
4316         mono_register_jit_icall (mono_arm_throw_exception_by_token, "mono_arm_throw_exception_by_token", mono_create_icall_signature ("void"), TRUE);
4317
4318 #ifndef MONO_CROSS_COMPILE
4319 #ifdef HAVE_AEABI_READ_TP
4320         mono_register_jit_icall (__aeabi_read_tp, "__aeabi_read_tp", mono_create_icall_signature ("void"), TRUE);
4321 #endif
4322 #endif
4323 }
4324
4325 #define patch_lis_ori(ip,val) do {\
4326                 guint16 *__lis_ori = (guint16*)(ip);    \
4327                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
4328                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
4329         } while (0)
4330
4331 void
4332 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
4333 {
4334         MonoJumpInfo *patch_info;
4335         gboolean compile_aot = !run_cctors;
4336
4337         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
4338                 unsigned char *ip = patch_info->ip.i + code;
4339                 const unsigned char *target;
4340
4341                 if (patch_info->type == MONO_PATCH_INFO_SWITCH && !compile_aot) {
4342                         gpointer *jt = (gpointer*)(ip + 8);
4343                         int i;
4344                         /* jt is the inlined jump table, 2 instructions after ip
4345                          * In the normal case we store the absolute addresses,
4346                          * otherwise the displacements.
4347                          */
4348                         for (i = 0; i < patch_info->data.table->table_size; i++)
4349                                 jt [i] = code + (int)patch_info->data.table->table [i];
4350                         continue;
4351                 }
4352                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
4353
4354                 if (compile_aot) {
4355                         switch (patch_info->type) {
4356                         case MONO_PATCH_INFO_BB:
4357                         case MONO_PATCH_INFO_LABEL:
4358                                 break;
4359                         default:
4360                                 /* No need to patch these */
4361                                 continue;
4362                         }
4363                 }
4364
4365                 switch (patch_info->type) {
4366                 case MONO_PATCH_INFO_IP:
4367                         g_assert_not_reached ();
4368                         patch_lis_ori (ip, ip);
4369                         continue;
4370                 case MONO_PATCH_INFO_METHOD_REL:
4371                         g_assert_not_reached ();
4372                         *((gpointer *)(ip)) = code + patch_info->data.offset;
4373                         continue;
4374                 case MONO_PATCH_INFO_METHODCONST:
4375                 case MONO_PATCH_INFO_CLASS:
4376                 case MONO_PATCH_INFO_IMAGE:
4377                 case MONO_PATCH_INFO_FIELD:
4378                 case MONO_PATCH_INFO_VTABLE:
4379                 case MONO_PATCH_INFO_IID:
4380                 case MONO_PATCH_INFO_SFLDA:
4381                 case MONO_PATCH_INFO_LDSTR:
4382                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
4383                 case MONO_PATCH_INFO_LDTOKEN:
4384                         g_assert_not_reached ();
4385                         /* from OP_AOTCONST : lis + ori */
4386                         patch_lis_ori (ip, target);
4387                         continue;
4388                 case MONO_PATCH_INFO_R4:
4389                 case MONO_PATCH_INFO_R8:
4390                         g_assert_not_reached ();
4391                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
4392                         continue;
4393                 case MONO_PATCH_INFO_EXC_NAME:
4394                         g_assert_not_reached ();
4395                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
4396                         continue;
4397                 case MONO_PATCH_INFO_NONE:
4398                 case MONO_PATCH_INFO_BB_OVF:
4399                 case MONO_PATCH_INFO_EXC_OVF:
4400                         /* everything is dealt with at epilog output time */
4401                         continue;
4402                 default:
4403                         break;
4404                 }
4405                 arm_patch_general (domain, ip, target);
4406         }
4407 }
4408
4409 /*
4410  * Stack frame layout:
4411  * 
4412  *   ------------------- fp
4413  *      MonoLMF structure or saved registers
4414  *   -------------------
4415  *      locals
4416  *   -------------------
4417  *      spilled regs
4418  *   -------------------
4419  *      optional 8 bytes for tracing
4420  *   -------------------
4421  *      param area             size is cfg->param_area
4422  *   ------------------- sp
4423  */
4424 guint8 *
4425 mono_arch_emit_prolog (MonoCompile *cfg)
4426 {
4427         MonoMethod *method = cfg->method;
4428         MonoBasicBlock *bb;
4429         MonoMethodSignature *sig;
4430         MonoInst *inst;
4431         int alloc_size, pos, max_offset, i, rot_amount;
4432         guint8 *code;
4433         CallInfo *cinfo;
4434         int tracing = 0;
4435         int lmf_offset = 0;
4436         int prev_sp_offset, reg_offset;
4437
4438         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
4439                 tracing = 1;
4440
4441         sig = mono_method_signature (method);
4442         cfg->code_size = 256 + sig->param_count * 20;
4443         code = cfg->native_code = g_malloc (cfg->code_size);
4444
4445         mono_emit_unwind_op_def_cfa (cfg, code, ARMREG_SP, 0);
4446
4447         ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
4448
4449         alloc_size = cfg->stack_offset;
4450         pos = 0;
4451
4452         if (!method->save_lmf) {
4453                 /* We save SP by storing it into IP and saving IP */
4454                 ARM_PUSH (code, (cfg->used_int_regs | (1 << ARMREG_IP) | (1 << ARMREG_LR)));
4455                 prev_sp_offset = 8; /* ip and lr */
4456                 for (i = 0; i < 16; ++i) {
4457                         if (cfg->used_int_regs & (1 << i))
4458                                 prev_sp_offset += 4;
4459                 }
4460                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
4461                 reg_offset = 0;
4462                 for (i = 0; i < 16; ++i) {
4463                         if ((cfg->used_int_regs & (1 << i)) || (i == ARMREG_IP) || (i == ARMREG_LR)) {
4464                                 mono_emit_unwind_op_offset (cfg, code, i, (- prev_sp_offset) + reg_offset);
4465                                 reg_offset += 4;
4466                         }
4467                 }
4468         } else {
4469                 ARM_PUSH (code, 0x5ff0);
4470                 prev_sp_offset = 4 * 10; /* all but r0-r3, sp and pc */
4471                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset);
4472                 reg_offset = 0;
4473                 for (i = 0; i < 16; ++i) {
4474                         if ((i > ARMREG_R3) && (i != ARMREG_SP) && (i != ARMREG_PC)) {
4475                                 mono_emit_unwind_op_offset (cfg, code, i, (- prev_sp_offset) + reg_offset);
4476                                 reg_offset += 4;
4477                         }
4478                 }
4479                 pos += sizeof (MonoLMF) - prev_sp_offset;
4480                 lmf_offset = pos;
4481         }
4482         alloc_size += pos;
4483         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
4484         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
4485                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
4486                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
4487         }
4488
4489         /* the stack used in the pushed regs */
4490         if (prev_sp_offset & 4)
4491                 alloc_size += 4;
4492         cfg->stack_usage = alloc_size;
4493         if (alloc_size) {
4494                 if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
4495                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
4496                 } else {
4497                         code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
4498                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
4499                 }
4500                 mono_emit_unwind_op_def_cfa_offset (cfg, code, prev_sp_offset + alloc_size);
4501         }
4502         if (cfg->frame_reg != ARMREG_SP) {
4503                 ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
4504                 mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg);
4505         }
4506         //g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
4507         prev_sp_offset += alloc_size;
4508
4509         /* compute max_offset in order to use short forward jumps
4510          * we could skip do it on arm because the immediate displacement
4511          * for jumps is large enough, it may be useful later for constant pools
4512          */
4513         max_offset = 0;
4514         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
4515                 MonoInst *ins = bb->code;
4516                 bb->max_offset = max_offset;
4517
4518                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
4519                         max_offset += 6; 
4520
4521                 MONO_BB_FOR_EACH_INS (bb, ins)
4522                         max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN];
4523         }
4524
4525         /* store runtime generic context */
4526         if (cfg->rgctx_var) {
4527                 MonoInst *ins = cfg->rgctx_var;
4528
4529                 g_assert (ins->opcode == OP_REGOFFSET);
4530
4531                 if (arm_is_imm12 (ins->inst_offset)) {
4532                         ARM_STR_IMM (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ins->inst_offset);
4533                 } else {
4534                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4535                         ARM_STR_REG_REG (code, MONO_ARCH_RGCTX_REG, ins->inst_basereg, ARMREG_LR);
4536                 }
4537         }
4538
4539         /* load arguments allocated to register from the stack */
4540         pos = 0;
4541
4542         cinfo = get_call_info (NULL, sig, sig->pinvoke);
4543
4544         if (MONO_TYPE_ISSTRUCT (sig->ret) && cinfo->ret.storage != RegTypeStructByVal) {
4545                 ArgInfo *ainfo = &cinfo->ret;
4546                 inst = cfg->vret_addr;
4547                 g_assert (arm_is_imm12 (inst->inst_offset));
4548                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4549         }
4550
4551         if (sig->call_convention == MONO_CALL_VARARG) {
4552                 ArgInfo *cookie = &cinfo->sig_cookie;
4553
4554                 /* Save the sig cookie address */
4555                 g_assert (cookie->storage == RegTypeBase);
4556
4557                 g_assert (arm_is_imm12 (prev_sp_offset + cookie->offset));
4558                 g_assert (arm_is_imm12 (cfg->sig_cookie));
4559                 ARM_ADD_REG_IMM8 (code, ARMREG_IP, cfg->frame_reg, prev_sp_offset + cookie->offset);
4560                 ARM_STR_IMM (code, ARMREG_IP, cfg->frame_reg, cfg->sig_cookie);
4561         }
4562
4563         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
4564                 ArgInfo *ainfo = cinfo->args + i;
4565                 inst = cfg->args [pos];
4566                 
4567                 if (cfg->verbose_level > 2)
4568                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->storage);
4569                 if (inst->opcode == OP_REGVAR) {
4570                         if (ainfo->storage == RegTypeGeneral)
4571                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
4572                         else if (ainfo->storage == RegTypeFP) {
4573                                 g_assert_not_reached ();
4574                         } else if (ainfo->storage == RegTypeBase) {
4575                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
4576                                         ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
4577                                 } else {
4578                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4579                                         ARM_LDR_REG_REG (code, inst->dreg, ARMREG_SP, ARMREG_IP);
4580                                 }
4581                         } else
4582                                 g_assert_not_reached ();
4583
4584                         if (cfg->verbose_level > 2)
4585                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
4586                 } else {
4587                         /* the argument should be put on the stack: FIXME handle size != word  */
4588                         if (ainfo->storage == RegTypeGeneral || ainfo->storage == RegTypeIRegPair) {
4589                                 switch (ainfo->size) {
4590                                 case 1:
4591                                         if (arm_is_imm12 (inst->inst_offset))
4592                                                 ARM_STRB_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4593                                         else {
4594                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4595                                                 ARM_STRB_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
4596                                         }
4597                                         break;
4598                                 case 2:
4599                                         if (arm_is_imm8 (inst->inst_offset)) {
4600                                                 ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4601                                         } else {
4602                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4603                                                 ARM_STRH_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
4604                                         }
4605                                         break;
4606                                 case 8:
4607                                         g_assert (arm_is_imm12 (inst->inst_offset));
4608                                         ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4609                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
4610                                         ARM_STR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
4611                                         break;
4612                                 default:
4613                                         if (arm_is_imm12 (inst->inst_offset)) {
4614                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
4615                                         } else {
4616                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4617                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
4618                                         }
4619                                         break;
4620                                 }
4621                         } else if (ainfo->storage == RegTypeBaseGen) {
4622                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
4623                                 g_assert (arm_is_imm12 (inst->inst_offset));
4624                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
4625                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
4626                                 ARM_STR_IMM (code, ARMREG_R3, inst->inst_basereg, inst->inst_offset);
4627                         } else if (ainfo->storage == RegTypeBase) {
4628                                 if (arm_is_imm12 (prev_sp_offset + ainfo->offset)) {
4629                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
4630                                 } else {
4631                                         code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset);
4632                                         ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
4633                                 }
4634
4635                                 switch (ainfo->size) {
4636                                 case 1:
4637                                         if (arm_is_imm8 (inst->inst_offset)) {
4638                                                 ARM_STRB_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
4639                                         } else {
4640                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4641                                                 ARM_STRB_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
4642                                         }
4643                                         break;
4644                                 case 2:
4645                                         if (arm_is_imm8 (inst->inst_offset)) {
4646                                                 ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
4647                                         } else {
4648                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4649                                                 ARM_STRH_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
4650                                         }
4651                                         break;
4652                                 case 8:
4653                                         if (arm_is_imm12 (inst->inst_offset)) {
4654                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
4655                                         } else {
4656                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4657                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
4658                                         }
4659                                         if (arm_is_imm12 (prev_sp_offset + ainfo->offset + 4)) {
4660                                                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset + 4));
4661                                         } else {
4662                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, prev_sp_offset + ainfo->offset + 4);
4663                                                 ARM_LDR_REG_REG (code, ARMREG_LR, ARMREG_SP, ARMREG_IP);
4664                                         }
4665                                         if (arm_is_imm12 (inst->inst_offset + 4)) {
4666                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
4667                                         } else {
4668                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset + 4);
4669                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
4670                                         }
4671                                         break;
4672                                 default:
4673                                         if (arm_is_imm12 (inst->inst_offset)) {
4674                                                 ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
4675                                         } else {
4676                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
4677                                                 ARM_STR_REG_REG (code, ARMREG_LR, inst->inst_basereg, ARMREG_IP);
4678                                         }
4679                                         break;
4680                                 }
4681                         } else if (ainfo->storage == RegTypeFP) {
4682                                 g_assert_not_reached ();
4683                         } else if (ainfo->storage == RegTypeStructByVal) {
4684                                 int doffset = inst->inst_offset;
4685                                 int soffset = 0;
4686                                 int cur_reg;
4687                                 int size = 0;
4688                                 size = mini_type_stack_size_full (cfg->generic_sharing_context, inst->inst_vtype, NULL, sig->pinvoke);
4689                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
4690                                         if (arm_is_imm12 (doffset)) {
4691                                                 ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
4692                                         } else {
4693                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, doffset);
4694                                                 ARM_STR_REG_REG (code, ainfo->reg + cur_reg, inst->inst_basereg, ARMREG_IP);
4695                                         }
4696                                         soffset += sizeof (gpointer);
4697                                         doffset += sizeof (gpointer);
4698                                 }
4699                                 if (ainfo->vtsize) {
4700                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4701                                         //g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
4702                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
4703                                 }
4704                         } else if (ainfo->storage == RegTypeStructByAddr) {
4705                                 g_assert_not_reached ();
4706                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
4707                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
4708                         } else
4709                                 g_assert_not_reached ();
4710                 }
4711                 pos++;
4712         }
4713
4714         if (method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
4715                 if (cfg->compile_aot)
4716                         /* AOT code is only used in the root domain */
4717                         code = mono_arm_emit_load_imm (code, ARMREG_R0, 0);
4718                 else
4719                         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->domain);
4720                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4721                              (gpointer)"mono_jit_thread_attach");
4722                 code = emit_call_seq (cfg, code);
4723         }
4724
4725         if (method->save_lmf) {
4726                 gboolean get_lmf_fast = FALSE;
4727
4728 #ifdef HAVE_AEABI_READ_TP
4729                 gint32 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
4730
4731                 if (lmf_addr_tls_offset != -1) {
4732                         get_lmf_fast = TRUE;
4733
4734                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4735                                                                  (gpointer)"__aeabi_read_tp");
4736                         code = emit_call_seq (cfg, code);
4737
4738                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_R0, lmf_addr_tls_offset);
4739                         get_lmf_fast = TRUE;
4740                 }
4741 #endif
4742                 if (!get_lmf_fast) {
4743                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
4744                                                                  (gpointer)"mono_get_lmf_addr");
4745                         code = emit_call_seq (cfg, code);
4746                 }
4747                 /* we build the MonoLMF structure on the stack - see mini-arm.h */
4748                 /* lmf_offset is the offset from the previous stack pointer,
4749                  * alloc_size is the total stack space allocated, so the offset
4750                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
4751                  * The pointer to the struct is put in r1 (new_lmf).
4752                  * r2 is used as scratch
4753                  * The callee-saved registers are already in the MonoLMF structure
4754                  */
4755                 code = emit_big_add (code, ARMREG_R1, ARMREG_SP, alloc_size - lmf_offset);
4756                 /* r0 is the result from mono_get_lmf_addr () */
4757                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
4758                 /* new_lmf->previous_lmf = *lmf_addr */
4759                 ARM_LDR_IMM (code, ARMREG_R2, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
4760                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
4761                 /* *(lmf_addr) = r1 */
4762                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
4763                 /* Skip method (only needed for trampoline LMF frames) */
4764                 ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
4765                 /* save the current IP */
4766                 ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
4767                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
4768         }
4769
4770         if (tracing)
4771                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
4772
4773         if (cfg->arch.seq_point_info_var) {
4774                 MonoInst *ins = cfg->arch.seq_point_info_var;
4775
4776                 /* Initialize the variable from a GOT slot */
4777                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_SEQ_POINT_INFO, cfg->method);
4778                 ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
4779                 ARM_B (code, 0);
4780                 *(gpointer*)code = NULL;
4781                 code += 4;
4782                 ARM_LDR_REG_REG (code, ARMREG_R0, ARMREG_PC, ARMREG_R0);
4783
4784                 g_assert (ins->opcode == OP_REGOFFSET);
4785
4786                 if (arm_is_imm12 (ins->inst_offset)) {
4787                         ARM_STR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
4788                 } else {
4789                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4790                         ARM_STR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
4791                 }
4792         }
4793
4794         /* Initialize ss_trigger_page_var */
4795         {
4796                 MonoInst *info_var = cfg->arch.seq_point_info_var;
4797                 MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
4798                 int dreg = ARMREG_LR;
4799
4800                 if (info_var) {
4801                         g_assert (info_var->opcode == OP_REGOFFSET);
4802                         g_assert (arm_is_imm12 (info_var->inst_offset));
4803
4804                         ARM_LDR_IMM (code, dreg, info_var->inst_basereg, info_var->inst_offset);
4805                         /* Load the trigger page addr */
4806                         ARM_LDR_IMM (code, dreg, dreg, G_STRUCT_OFFSET (SeqPointInfo, ss_trigger_page));
4807                         ARM_STR_IMM (code, dreg, ss_trigger_page_var->inst_basereg, ss_trigger_page_var->inst_offset);
4808                 }
4809         }
4810
4811         cfg->code_len = code - cfg->native_code;
4812         g_assert (cfg->code_len < cfg->code_size);
4813         g_free (cinfo);
4814
4815         return code;
4816 }
4817
4818 void
4819 mono_arch_emit_epilog (MonoCompile *cfg)
4820 {
4821         MonoMethod *method = cfg->method;
4822         int pos, i, rot_amount;
4823         int max_epilog_size = 16 + 20*4;
4824         guint8 *code;
4825         CallInfo *cinfo;
4826
4827         if (cfg->method->save_lmf)
4828                 max_epilog_size += 128;
4829         
4830         if (mono_jit_trace_calls != NULL)
4831                 max_epilog_size += 50;
4832
4833         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
4834                 max_epilog_size += 50;
4835
4836         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4837                 cfg->code_size *= 2;
4838                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4839                 mono_jit_stats.code_reallocs++;
4840         }
4841
4842         /*
4843          * Keep in sync with OP_JMP
4844          */
4845         code = cfg->native_code + cfg->code_len;
4846
4847         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
4848                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
4849         }
4850         pos = 0;
4851
4852         /* Load returned vtypes into registers if needed */
4853         cinfo = cfg->arch.cinfo;
4854         if (cinfo->ret.storage == RegTypeStructByVal) {
4855                 MonoInst *ins = cfg->ret;
4856
4857                 if (arm_is_imm12 (ins->inst_offset)) {
4858                         ARM_LDR_IMM (code, ARMREG_R0, ins->inst_basereg, ins->inst_offset);
4859                 } else {
4860                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
4861                         ARM_LDR_REG_REG (code, ARMREG_R0, ins->inst_basereg, ARMREG_LR);
4862                 }
4863         }
4864
4865         if (method->save_lmf) {
4866                 int lmf_offset;
4867                 /* all but r0-r3, sp and pc */
4868                 pos += sizeof (MonoLMF) - (4 * 10);
4869                 lmf_offset = pos;
4870                 /* r2 contains the pointer to the current LMF */
4871                 code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, cfg->stack_usage - lmf_offset);
4872                 /* ip = previous_lmf */
4873                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
4874                 /* lr = lmf_addr */
4875                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
4876                 /* *(lmf_addr) = previous_lmf */
4877                 ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
4878                 /* FIXME: speedup: there is no actual need to restore the registers if
4879                  * we didn't actually change them (idea from Zoltan).
4880                  */
4881                 /* restore iregs */
4882                 /* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
4883                 ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_R2, (sizeof (MonoLMF) - 10 * sizeof (gulong)));
4884                 ARM_POP_NWB (code, 0xaff0); /* restore ip to sp and lr to pc */
4885         } else {
4886                 if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
4887                         ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
4888                 } else {
4889                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage);
4890                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
4891                 }
4892                 /* FIXME: add v4 thumb interworking support */
4893                 ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP) | (1 << ARMREG_PC)));
4894         }
4895
4896         cfg->code_len = code - cfg->native_code;
4897
4898         g_assert (cfg->code_len < cfg->code_size);
4899
4900 }
4901
4902 /* remove once throw_exception_by_name is eliminated */
4903 static int
4904 exception_id_by_name (const char *name)
4905 {
4906         if (strcmp (name, "IndexOutOfRangeException") == 0)
4907                 return MONO_EXC_INDEX_OUT_OF_RANGE;
4908         if (strcmp (name, "OverflowException") == 0)
4909                 return MONO_EXC_OVERFLOW;
4910         if (strcmp (name, "ArithmeticException") == 0)
4911                 return MONO_EXC_ARITHMETIC;
4912         if (strcmp (name, "DivideByZeroException") == 0)
4913                 return MONO_EXC_DIVIDE_BY_ZERO;
4914         if (strcmp (name, "InvalidCastException") == 0)
4915                 return MONO_EXC_INVALID_CAST;
4916         if (strcmp (name, "NullReferenceException") == 0)
4917                 return MONO_EXC_NULL_REF;
4918         if (strcmp (name, "ArrayTypeMismatchException") == 0)
4919                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
4920         g_error ("Unknown intrinsic exception %s\n", name);
4921         return -1;
4922 }
4923
4924 void
4925 mono_arch_emit_exceptions (MonoCompile *cfg)
4926 {
4927         MonoJumpInfo *patch_info;
4928         int i;
4929         guint8 *code;
4930         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
4931         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
4932         int max_epilog_size = 50;
4933
4934         /* count the number of exception infos */
4935      
4936         /* 
4937          * make sure we have enough space for exceptions
4938          */
4939         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4940                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
4941                         i = exception_id_by_name (patch_info->data.target);
4942                         if (!exc_throw_found [i]) {
4943                                 max_epilog_size += 32;
4944                                 exc_throw_found [i] = TRUE;
4945                         }
4946                 }
4947         }
4948
4949         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
4950                 cfg->code_size *= 2;
4951                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
4952                 mono_jit_stats.code_reallocs++;
4953         }
4954
4955         code = cfg->native_code + cfg->code_len;
4956
4957         /* add code to raise exceptions */
4958         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
4959                 switch (patch_info->type) {
4960                 case MONO_PATCH_INFO_EXC: {
4961                         MonoClass *exc_class;
4962                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
4963
4964                         i = exception_id_by_name (patch_info->data.target);
4965                         if (exc_throw_pos [i]) {
4966                                 arm_patch (ip, exc_throw_pos [i]);
4967                                 patch_info->type = MONO_PATCH_INFO_NONE;
4968                                 break;
4969                         } else {
4970                                 exc_throw_pos [i] = code;
4971                         }
4972                         arm_patch (ip, code);
4973
4974                         exc_class = mono_class_from_name (mono_defaults.corlib, "System", patch_info->data.name);
4975                         g_assert (exc_class);
4976
4977                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_LR);
4978                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
4979                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
4980                         patch_info->data.name = "mono_arch_throw_corlib_exception";
4981                         patch_info->ip.i = code - cfg->native_code;
4982                         ARM_BL (code, 0);
4983                         *(guint32*)(gpointer)code = exc_class->type_token;
4984                         code += 4;
4985                         break;
4986                 }
4987                 default:
4988                         /* do nothing */
4989                         break;
4990                 }
4991         }
4992
4993         cfg->code_len = code - cfg->native_code;
4994
4995         g_assert (cfg->code_len < cfg->code_size);
4996
4997 }
4998
4999 static gboolean tls_offset_inited = FALSE;
5000
5001 void
5002 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
5003 {
5004         if (!tls_offset_inited) {
5005                 tls_offset_inited = TRUE;
5006
5007                 lmf_tls_offset = mono_get_lmf_tls_offset ();
5008                 lmf_addr_tls_offset = mono_get_lmf_addr_tls_offset ();
5009         }
5010 }
5011
5012 void
5013 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
5014 {
5015 }
5016
5017 MonoInst*
5018 mono_arch_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
5019 {
5020         /* FIXME: */
5021         return NULL;
5022 }
5023
5024 gboolean
5025 mono_arch_print_tree (MonoInst *tree, int arity)
5026 {
5027         return 0;
5028 }
5029
5030 MonoInst*
5031 mono_arch_get_domain_intrinsic (MonoCompile* cfg)
5032 {
5033         return mono_get_domain_intrinsic (cfg);
5034 }
5035
5036 guint32
5037 mono_arch_get_patch_offset (guint8 *code)
5038 {
5039         /* OP_AOTCONST */
5040         return 8;
5041 }
5042
5043 void
5044 mono_arch_flush_register_windows (void)
5045 {
5046 }
5047
5048 #ifdef MONO_ARCH_HAVE_IMT
5049
5050 void
5051 mono_arch_emit_imt_argument (MonoCompile *cfg, MonoCallInst *call, MonoInst *imt_arg)
5052 {
5053         if (cfg->compile_aot) {
5054                 int method_reg = mono_alloc_ireg (cfg);
5055                 MonoInst *ins;
5056
5057                 call->dynamic_imt_arg = TRUE;
5058
5059                 if (imt_arg) {
5060                         mono_call_inst_add_outarg_reg (cfg, call, imt_arg->dreg, ARMREG_V5, FALSE);
5061                 } else {
5062                         MONO_INST_NEW (cfg, ins, OP_AOTCONST);
5063                         ins->dreg = method_reg;
5064                         ins->inst_p0 = call->method;
5065                         ins->inst_c1 = MONO_PATCH_INFO_METHODCONST;
5066                         MONO_ADD_INS (cfg->cbb, ins);
5067
5068                         mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
5069                 }
5070         } else if (cfg->generic_context) {
5071
5072                 /* Always pass in a register for simplicity */
5073                 call->dynamic_imt_arg = TRUE;
5074
5075                 cfg->uses_rgctx_reg = TRUE;
5076
5077                 if (imt_arg) {
5078                         mono_call_inst_add_outarg_reg (cfg, call, imt_arg->dreg, ARMREG_V5, FALSE);
5079                 } else {
5080                         MonoInst *ins;
5081                         int method_reg = mono_alloc_preg (cfg);
5082
5083                         MONO_INST_NEW (cfg, ins, OP_PCONST);
5084                         ins->inst_p0 = call->method;
5085                         ins->dreg = method_reg;
5086                         MONO_ADD_INS (cfg->cbb, ins);
5087
5088                         mono_call_inst_add_outarg_reg (cfg, call, method_reg, ARMREG_V5, FALSE);
5089                 }
5090         }
5091 }
5092
5093 MonoMethod*
5094 mono_arch_find_imt_method (mgreg_t *regs, guint8 *code)
5095 {
5096         guint32 *code_ptr = (guint32*)code;
5097         code_ptr -= 2;
5098         /* The IMT value is stored in the code stream right after the LDC instruction. */
5099         if (!IS_LDR_PC (code_ptr [0])) {
5100                 g_warning ("invalid code stream, instruction before IMT value is not a LDC in %s() (code %p value 0: 0x%x -1: 0x%x -2: 0x%x)", __FUNCTION__, code, code_ptr [2], code_ptr [1], code_ptr [0]);
5101                 g_assert (IS_LDR_PC (code_ptr [0]));
5102         }
5103         if (code_ptr [1] == 0)
5104                 /* This is AOTed code, the IMT method is in V5 */
5105                 return (MonoMethod*)regs [ARMREG_V5];
5106         else
5107                 return (MonoMethod*) code_ptr [1];
5108 }
5109
5110 MonoVTable*
5111 mono_arch_find_static_call_vtable (mgreg_t *regs, guint8 *code)
5112 {
5113         return (MonoVTable*) regs [MONO_ARCH_RGCTX_REG];
5114 }
5115
5116 #define ENABLE_WRONG_METHOD_CHECK 0
5117 #define BASE_SIZE (6 * 4)
5118 #define BSEARCH_ENTRY_SIZE (4 * 4)
5119 #define CMP_SIZE (3 * 4)
5120 #define BRANCH_SIZE (1 * 4)
5121 #define CALL_SIZE (2 * 4)
5122 #define WMC_SIZE (5 * 4)
5123 #define DISTANCE(A, B) (((gint32)(B)) - ((gint32)(A)))
5124
5125 static arminstr_t *
5126 arm_emit_value_and_patch_ldr (arminstr_t *code, arminstr_t *target, guint32 value)
5127 {
5128         guint32 delta = DISTANCE (target, code);
5129         delta -= 8;
5130         g_assert (delta >= 0 && delta <= 0xFFF);
5131         *target = *target | delta;
5132         *code = value;
5133         return code + 1;
5134 }
5135
5136 gpointer
5137 mono_arch_build_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count,
5138         gpointer fail_tramp)
5139 {
5140         int size, i, extra_space = 0;
5141         arminstr_t *code, *start, *vtable_target = NULL;
5142         gboolean large_offsets = FALSE;
5143         guint32 **constant_pool_starts;
5144
5145         size = BASE_SIZE;
5146         constant_pool_starts = g_new0 (guint32*, count);
5147
5148         /* 
5149          * We might be called with a fail_tramp from the IMT builder code even if
5150          * MONO_ARCH_HAVE_GENERALIZED_IMT_THUNK is not defined.
5151          */
5152         //g_assert (!fail_tramp);
5153
5154         for (i = 0; i < count; ++i) {
5155                 MonoIMTCheckItem *item = imt_entries [i];
5156                 if (item->is_equals) {
5157                         if (!arm_is_imm12 (DISTANCE (vtable, &vtable->vtable[item->value.vtable_slot]))) {
5158                                 item->chunk_size += 32;
5159                                 large_offsets = TRUE;
5160                         }
5161
5162                         if (item->check_target_idx) {
5163                                 if (!item->compare_done)
5164                                         item->chunk_size += CMP_SIZE;
5165                                 item->chunk_size += BRANCH_SIZE;
5166                         } else {
5167 #if ENABLE_WRONG_METHOD_CHECK
5168                                 item->chunk_size += WMC_SIZE;
5169 #endif
5170                         }
5171                         item->chunk_size += CALL_SIZE;
5172                 } else {
5173                         item->chunk_size += BSEARCH_ENTRY_SIZE;
5174                         imt_entries [item->check_target_idx]->compare_done = TRUE;
5175                 }
5176                 size += item->chunk_size;
5177         }
5178
5179         if (large_offsets)
5180                 size += 4 * count; /* The ARM_ADD_REG_IMM to pop the stack */
5181
5182         start = code = mono_domain_code_reserve (domain, size);
5183
5184 #if DEBUG_IMT
5185         printf ("building IMT thunk for class %s %s entries %d code size %d code at %p end %p vtable %p\n", vtable->klass->name_space, vtable->klass->name, count, size, start, ((guint8*)start) + size, vtable);
5186         for (i = 0; i < count; ++i) {
5187                 MonoIMTCheckItem *item = imt_entries [i];
5188                 printf ("method %d (%p) %s vtable slot %p is_equals %d chunk size %d\n", i, item->key, item->key->name, &vtable->vtable [item->value.vtable_slot], item->is_equals, item->chunk_size);
5189         }
5190 #endif
5191
5192         if (large_offsets)
5193                 ARM_PUSH4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
5194         else
5195                 ARM_PUSH2 (code, ARMREG_R0, ARMREG_R1);
5196         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_LR, -4);
5197         vtable_target = code;
5198         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
5199
5200         /* R0 == 0 means we are called from AOT code. In this case, V5 contains the IMT method */
5201         ARM_CMP_REG_IMM8 (code, ARMREG_R0, 0);
5202         ARM_MOV_REG_REG_COND (code, ARMREG_R0, ARMREG_V5, ARMCOND_EQ);
5203
5204         for (i = 0; i < count; ++i) {
5205                 MonoIMTCheckItem *item = imt_entries [i];
5206                 arminstr_t *imt_method = NULL, *vtable_offset_ins = NULL;
5207                 gint32 vtable_offset;
5208
5209                 item->code_target = (guint8*)code;
5210
5211                 if (item->is_equals) {
5212                         if (item->check_target_idx) {
5213                                 if (!item->compare_done) {
5214                                         imt_method = code;
5215                                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
5216                                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
5217                                 }
5218                                 item->jmp_code = (guint8*)code;
5219                                 ARM_B_COND (code, ARMCOND_NE, 0);
5220                         } else {
5221                                 /*Enable the commented code to assert on wrong method*/
5222 #if ENABLE_WRONG_METHOD_CHECK
5223                                 imt_method = code;
5224                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
5225                                 ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
5226                                 ARM_B_COND (code, ARMCOND_NE, 1);
5227
5228                                 ARM_DBRK (code);
5229 #endif
5230                         }
5231
5232                         vtable_offset = DISTANCE (vtable, &vtable->vtable[item->value.vtable_slot]);
5233                         if (!arm_is_imm12 (vtable_offset)) {
5234                                 /* 
5235                                  * We need to branch to a computed address but we don't have
5236                                  * a free register to store it, since IP must contain the 
5237                                  * vtable address. So we push the two values to the stack, and
5238                                  * load them both using LDM.
5239                                  */
5240                                 /* Compute target address */
5241                                 vtable_offset_ins = code;
5242                                 ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
5243                                 ARM_LDR_REG_REG (code, ARMREG_R1, ARMREG_IP, ARMREG_R1);
5244                                 /* Save it to the fourth slot */
5245                                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_SP, 3 * sizeof (gpointer));
5246                                 /* Restore registers and branch */
5247                                 ARM_POP4 (code, ARMREG_R0, ARMREG_R1, ARMREG_IP, ARMREG_PC);
5248                                 
5249                                 code = arm_emit_value_and_patch_ldr (code, vtable_offset_ins, vtable_offset);
5250                         } else {
5251                                 ARM_POP2 (code, ARMREG_R0, ARMREG_R1);
5252                                 if (large_offsets)
5253                                         ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 2 * sizeof (gpointer));
5254                                 ARM_LDR_IMM (code, ARMREG_PC, ARMREG_IP, vtable_offset);
5255                         }
5256
5257                         if (imt_method)
5258                                 code = arm_emit_value_and_patch_ldr (code, imt_method, (guint32)item->key);
5259
5260                         /*must emit after unconditional branch*/
5261                         if (vtable_target) {
5262                                 code = arm_emit_value_and_patch_ldr (code, vtable_target, (guint32)vtable);
5263                                 item->chunk_size += 4;
5264                                 vtable_target = NULL;
5265                         }
5266
5267                         /*We reserve the space for bsearch IMT values after the first entry with an absolute jump*/
5268                         constant_pool_starts [i] = code;
5269                         if (extra_space) {
5270                                 code += extra_space;
5271                                 extra_space = 0;
5272                         }
5273                 } else {
5274                         ARM_LDR_IMM (code, ARMREG_R1, ARMREG_PC, 0);
5275                         ARM_CMP_REG_REG (code, ARMREG_R0, ARMREG_R1);
5276
5277                         item->jmp_code = (guint8*)code;
5278                         ARM_B_COND (code, ARMCOND_GE, 0);
5279                         ++extra_space;
5280                 }
5281         }
5282
5283         for (i = 0; i < count; ++i) {
5284                 MonoIMTCheckItem *item = imt_entries [i];
5285                 if (item->jmp_code) {
5286                         if (item->check_target_idx)
5287                                 arm_patch (item->jmp_code, imt_entries [item->check_target_idx]->code_target);
5288                 }
5289                 if (i > 0 && item->is_equals) {
5290                         int j;
5291                         arminstr_t *space_start = constant_pool_starts [i];
5292                         for (j = i - 1; j >= 0 && !imt_entries [j]->is_equals; --j) {
5293                                 space_start = arm_emit_value_and_patch_ldr (space_start, (arminstr_t*)imt_entries [j]->code_target, (guint32)imt_entries [j]->key);
5294                         }
5295                 }
5296         }
5297
5298 #if DEBUG_IMT
5299         {
5300                 char *buff = g_strdup_printf ("thunk_for_class_%s_%s_entries_%d", vtable->klass->name_space, vtable->klass->name, count);
5301                 mono_disassemble_code (NULL, (guint8*)start, size, buff);
5302                 g_free (buff);
5303         }
5304 #endif
5305
5306         g_free (constant_pool_starts);
5307
5308         mono_arch_flush_icache ((guint8*)start, size);
5309         mono_stats.imt_thunks_size += code - start;
5310
5311         g_assert (DISTANCE (start, code) <= size);
5312         return start;
5313 }
5314
5315 #endif
5316
5317 gpointer
5318 mono_arch_context_get_int_reg (MonoContext *ctx, int reg)
5319 {
5320         if (reg == ARMREG_SP)
5321                 return (gpointer)ctx->esp;
5322         else
5323                 return (gpointer)ctx->regs [reg];
5324 }
5325
5326 /*
5327  * mono_arch_set_breakpoint:
5328  *
5329  *   Set a breakpoint at the native code corresponding to JI at NATIVE_OFFSET.
5330  * The location should contain code emitted by OP_SEQ_POINT.
5331  */
5332 void
5333 mono_arch_set_breakpoint (MonoJitInfo *ji, guint8 *ip)
5334 {
5335         guint8 *code = ip;
5336         guint32 native_offset = ip - (guint8*)ji->code_start;
5337
5338         if (ji->from_aot) {
5339                 SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
5340
5341                 g_assert (native_offset % 4 == 0);
5342                 g_assert (info->bp_addrs [native_offset / 4] == 0);
5343                 info->bp_addrs [native_offset / 4] = bp_trigger_page;
5344         } else {
5345                 int dreg = ARMREG_LR;
5346
5347                 /* Read from another trigger page */
5348                 ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
5349                 ARM_B (code, 0);
5350                 *(int*)code = (int)bp_trigger_page;
5351                 code += 4;
5352                 ARM_LDR_IMM (code, dreg, dreg, 0);
5353
5354                 mono_arch_flush_icache (code - 16, 16);
5355
5356 #if 0
5357                 /* This is currently implemented by emitting an SWI instruction, which 
5358                  * qemu/linux seems to convert to a SIGILL.
5359                  */
5360                 *(int*)code = (0xef << 24) | 8;
5361                 code += 4;
5362                 mono_arch_flush_icache (code - 4, 4);
5363 #endif
5364         }
5365 }
5366
5367 /*
5368  * mono_arch_clear_breakpoint:
5369  *
5370  *   Clear the breakpoint at IP.
5371  */
5372 void
5373 mono_arch_clear_breakpoint (MonoJitInfo *ji, guint8 *ip)
5374 {
5375         guint8 *code = ip;
5376         int i;
5377
5378         if (ji->from_aot) {
5379                 guint32 native_offset = ip - (guint8*)ji->code_start;
5380                 SeqPointInfo *info = mono_arch_get_seq_point_info (mono_domain_get (), ji->code_start);
5381
5382                 g_assert (native_offset % 4 == 0);
5383                 g_assert (info->bp_addrs [native_offset / 4] == bp_trigger_page);
5384                 info->bp_addrs [native_offset / 4] = 0;
5385         } else {
5386                 for (i = 0; i < 4; ++i)
5387                         ARM_NOP (code);
5388
5389                 mono_arch_flush_icache (ip, code - ip);
5390         }
5391 }
5392         
5393 /*
5394  * mono_arch_start_single_stepping:
5395  *
5396  *   Start single stepping.
5397  */
5398 void
5399 mono_arch_start_single_stepping (void)
5400 {
5401         mono_mprotect (ss_trigger_page, mono_pagesize (), 0);
5402 }
5403         
5404 /*
5405  * mono_arch_stop_single_stepping:
5406  *
5407  *   Stop single stepping.
5408  */
5409 void
5410 mono_arch_stop_single_stepping (void)
5411 {
5412         mono_mprotect (ss_trigger_page, mono_pagesize (), MONO_MMAP_READ);
5413 }
5414
5415 #if __APPLE__
5416 #define DBG_SIGNAL SIGBUS
5417 #else
5418 #define DBG_SIGNAL SIGSEGV
5419 #endif
5420
5421 /*
5422  * mono_arch_is_single_step_event:
5423  *
5424  *   Return whenever the machine state in SIGCTX corresponds to a single
5425  * step event.
5426  */
5427 gboolean
5428 mono_arch_is_single_step_event (void *info, void *sigctx)
5429 {
5430         siginfo_t *sinfo = info;
5431
5432         /* Sometimes the address is off by 4 */
5433         if (sinfo->si_addr >= ss_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)ss_trigger_page + 128)
5434                 return TRUE;
5435         else
5436                 return FALSE;
5437 }
5438
5439 /*
5440  * mono_arch_is_breakpoint_event:
5441  *
5442  *   Return whenever the machine state in SIGCTX corresponds to a breakpoint event.
5443  */
5444 gboolean
5445 mono_arch_is_breakpoint_event (void *info, void *sigctx)
5446 {
5447         siginfo_t *sinfo = info;
5448
5449         if (sinfo->si_signo == DBG_SIGNAL) {
5450                 /* Sometimes the address is off by 4 */
5451                 if (sinfo->si_addr >= bp_trigger_page && (guint8*)sinfo->si_addr <= (guint8*)bp_trigger_page + 128)
5452                         return TRUE;
5453                 else
5454                         return FALSE;
5455         } else {
5456                 return FALSE;
5457         }
5458 }
5459
5460 guint8*
5461 mono_arch_get_ip_for_breakpoint (MonoJitInfo *ji, MonoContext *ctx)
5462 {
5463         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
5464
5465         if (ji->from_aot)
5466                 ip -= 6 * 4;
5467         else
5468                 ip -= 12;
5469
5470         return ip;
5471 }
5472
5473 guint8*
5474 mono_arch_get_ip_for_single_step (MonoJitInfo *ji, MonoContext *ctx)
5475 {
5476         guint8 *ip = MONO_CONTEXT_GET_IP (ctx);
5477
5478         ip += 4;
5479
5480         return ip;
5481 }
5482
5483 /*
5484  * mono_arch_skip_breakpoint:
5485  *
5486  *   See mini-amd64.c for docs.
5487  */
5488 void
5489 mono_arch_skip_breakpoint (MonoContext *ctx)
5490 {
5491         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5492 }
5493
5494 /*
5495  * mono_arch_skip_single_step:
5496  *
5497  *   See mini-amd64.c for docs.
5498  */
5499 void
5500 mono_arch_skip_single_step (MonoContext *ctx)
5501 {
5502         MONO_CONTEXT_SET_IP (ctx, (guint8*)MONO_CONTEXT_GET_IP (ctx) + 4);
5503 }
5504
5505 /*
5506  * mono_arch_get_seq_point_info:
5507  *
5508  *   See mini-amd64.c for docs.
5509  */
5510 gpointer
5511 mono_arch_get_seq_point_info (MonoDomain *domain, guint8 *code)
5512 {
5513         SeqPointInfo *info;
5514         MonoJitInfo *ji;
5515
5516         // FIXME: Add a free function
5517
5518         mono_domain_lock (domain);
5519         info = g_hash_table_lookup (domain_jit_info (domain)->arch_seq_points, 
5520                                                                 code);
5521         mono_domain_unlock (domain);
5522
5523         if (!info) {
5524                 ji = mono_jit_info_table_find (domain, (char*)code);
5525                 g_assert (ji);
5526
5527                 info = g_malloc0 (sizeof (SeqPointInfo) + ji->code_size);
5528
5529                 info->ss_trigger_page = ss_trigger_page;
5530                 info->bp_trigger_page = bp_trigger_page;
5531
5532                 mono_domain_lock (domain);
5533                 g_hash_table_insert (domain_jit_info (domain)->arch_seq_points,
5534                                                          code, info);
5535                 mono_domain_unlock (domain);
5536         }
5537
5538         return info;
5539 }