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