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