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