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