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