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