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