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