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