New test.
[mono.git] / mono / mini / mini-arm.c
1 /*
2  * mini-arm.c: ARM backend for the Mono code generator
3  *
4  * Authors:
5  *   Paolo Molaro (lupus@ximian.com)
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *
8  * (C) 2003 Ximian, Inc.
9  */
10 #include "mini.h"
11 #include <string.h>
12
13 #include <mono/metadata/appdomain.h>
14 #include <mono/metadata/debug-helpers.h>
15
16 #include "mini-arm.h"
17 #include "inssel.h"
18 #include "cpu-arm.h"
19 #include "trace.h"
20 #include "mono/arch/arm/arm-fpa-codegen.h"
21
22 /*
23  * TODO:
24  * floating point support: on ARM it is a mess, there are at least 3
25  * different setups, each of which binary incompat with the other.
26  * 1) FPA: old and ugly, but unfortunately what current distros use
27  *    the double binary format has the two words swapped. 8 double registers.
28  *    Implemented usually by kernel emulation.
29  * 2) softfloat: the compiler emulates all the fp ops. Usually uses the
30  *    ugly swapped double format (I guess a softfloat-vfp exists, too, though).
31  * 3) VFP: the new and actually sensible and useful FP support. Implemented
32  *    in HW or kernel-emulated, requires new tools. I think this ios what symbian uses.
33  *
34  * The plan is to write the FPA support first. softfloat can be tested in a chroot.
35  */
36 int mono_exc_esp_offset = 0;
37
38 #define arm_is_imm12(v) ((v) > -4096 && (v) < 4096)
39 #define arm_is_imm8(v) ((v) > -256 && (v) < 256)
40 #define arm_is_fpimm8(v) ((v) >= -1020 && (v) <= 1020)
41
42 const char*
43 mono_arch_regname (int reg) {
44         static const char * rnames[] = {
45                 "arm_r0", "arm_r1", "arm_r2", "arm_r3", "arm_v1",
46                 "arm_v2", "arm_v3", "arm_v4", "arm_v5", "arm_v6",
47                 "arm_v7", "arm_fp", "arm_ip", "arm_sp", "arm_lr",
48                 "arm_pc"
49         };
50         if (reg >= 0 && reg < 16)
51                 return rnames [reg];
52         return "unknown";
53 }
54
55 const char*
56 mono_arch_fregname (int reg) {
57         static const char * rnames[] = {
58                 "arm_f0", "arm_f1", "arm_f2", "arm_f3", "arm_f4",
59                 "arm_f5", "arm_f6", "arm_f7", "arm_f8", "arm_f9",
60                 "arm_f10", "arm_f11", "arm_f12", "arm_f13", "arm_f14",
61                 "arm_f15", "arm_f16", "arm_f17", "arm_f18", "arm_f19",
62                 "arm_f20", "arm_f21", "arm_f22", "arm_f23", "arm_f24",
63                 "arm_f25", "arm_f26", "arm_f27", "arm_f28", "arm_f29",
64                 "arm_f30", "arm_f31"
65         };
66         if (reg >= 0 && reg < 32)
67                 return rnames [reg];
68         return "unknown";
69 }
70
71 static guint8*
72 emit_big_add (guint8 *code, int dreg, int sreg, int imm)
73 {
74         int imm8, rot_amount;
75         if ((imm8 = mono_arm_is_rotated_imm8 (imm, &rot_amount)) >= 0) {
76                 ARM_ADD_REG_IMM (code, dreg, sreg, imm8, rot_amount);
77                 return code;
78         }
79         g_assert (dreg != sreg);
80         code = mono_arm_emit_load_imm (code, dreg, imm);
81         ARM_ADD_REG_REG (code, dreg, dreg, sreg);
82         return code;
83 }
84
85 static guint8*
86 emit_memcpy (guint8 *code, int size, int dreg, int doffset, int sreg, int soffset)
87 {
88         /* we can use r0-r3, since this is called only for incoming args on the stack */
89         if (size > sizeof (gpointer) * 4) {
90                 guint8 *start_loop;
91                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
92                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
93                 start_loop = code = mono_arm_emit_load_imm (code, ARMREG_R2, size);
94                 ARM_LDR_IMM (code, ARMREG_R3, ARMREG_R0, 0);
95                 ARM_STR_IMM (code, ARMREG_R3, ARMREG_R1, 0);
96                 ARM_ADD_REG_IMM8 (code, ARMREG_R0, ARMREG_R0, 4);
97                 ARM_ADD_REG_IMM8 (code, ARMREG_R1, ARMREG_R1, 4);
98                 ARM_SUBS_REG_IMM8 (code, ARMREG_R2, ARMREG_R2, 4);
99                 ARM_B_COND (code, ARMCOND_NE, 0);
100                 arm_patch (code - 4, start_loop);
101                 return code;
102         }
103         if (arm_is_imm12 (doffset) && arm_is_imm12 (doffset + size) &&
104                         arm_is_imm12 (soffset) && arm_is_imm12 (soffset + size)) {
105                 while (size >= 4) {
106                         ARM_LDR_IMM (code, ARMREG_LR, sreg, soffset);
107                         ARM_STR_IMM (code, ARMREG_LR, dreg, doffset);
108                         doffset += 4;
109                         soffset += 4;
110                         size -= 4;
111                 }
112         } else if (size) {
113                 code = emit_big_add (code, ARMREG_R0, sreg, soffset);
114                 code = emit_big_add (code, ARMREG_R1, dreg, doffset);
115                 doffset = soffset = 0;
116                 while (size >= 4) {
117                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R0, soffset);
118                         ARM_STR_IMM (code, ARMREG_LR, ARMREG_R1, doffset);
119                         doffset += 4;
120                         soffset += 4;
121                         size -= 4;
122                 }
123         }
124         g_assert (size == 0);
125         return code;
126 }
127
128 /*
129  * mono_arch_get_argument_info:
130  * @csig:  a method signature
131  * @param_count: the number of parameters to consider
132  * @arg_info: an array to store the result infos
133  *
134  * Gathers information on parameters such as size, alignment and
135  * padding. arg_info should be large enought to hold param_count + 1 entries. 
136  *
137  * Returns the size of the activation frame.
138  */
139 int
140 mono_arch_get_argument_info (MonoMethodSignature *csig, int param_count, MonoJitArgumentInfo *arg_info)
141 {
142         int k, frame_size = 0;
143         int size, align, pad;
144         int offset = 8;
145
146         if (MONO_TYPE_ISSTRUCT (csig->ret)) { 
147                 frame_size += sizeof (gpointer);
148                 offset += 4;
149         }
150
151         arg_info [0].offset = offset;
152
153         if (csig->hasthis) {
154                 frame_size += sizeof (gpointer);
155                 offset += 4;
156         }
157
158         arg_info [0].size = frame_size;
159
160         for (k = 0; k < param_count; k++) {
161                 
162                 if (csig->pinvoke)
163                         size = mono_type_native_stack_size (csig->params [k], &align);
164                 else
165                         size = mono_type_stack_size (csig->params [k], &align);
166
167                 /* ignore alignment for now */
168                 align = 1;
169
170                 frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1); 
171                 arg_info [k].pad = pad;
172                 frame_size += size;
173                 arg_info [k + 1].pad = 0;
174                 arg_info [k + 1].size = size;
175                 offset += pad;
176                 arg_info [k + 1].offset = offset;
177                 offset += size;
178         }
179
180         align = MONO_ARCH_FRAME_ALIGNMENT;
181         frame_size += pad = (align - (frame_size & (align - 1))) & (align - 1);
182         arg_info [k].pad = pad;
183
184         return frame_size;
185 }
186
187 /*
188  * Initialize the cpu to execute managed code.
189  */
190 void
191 mono_arch_cpu_init (void)
192 {
193 }
194
195 /*
196  * This function returns the optimizations supported on this cpu.
197  */
198 guint32
199 mono_arch_cpu_optimizazions (guint32 *exclude_mask)
200 {
201         guint32 opts = 0;
202
203         /* no arm-specific optimizations yet */
204         *exclude_mask = 0;
205         return opts;
206 }
207
208 static gboolean
209 is_regsize_var (MonoType *t) {
210         if (t->byref)
211                 return TRUE;
212         t = mono_type_get_underlying_type (t);
213         switch (t->type) {
214         case MONO_TYPE_I4:
215         case MONO_TYPE_U4:
216         case MONO_TYPE_I:
217         case MONO_TYPE_U:
218         case MONO_TYPE_PTR:
219         case MONO_TYPE_FNPTR:
220                 return TRUE;
221         case MONO_TYPE_OBJECT:
222         case MONO_TYPE_STRING:
223         case MONO_TYPE_CLASS:
224         case MONO_TYPE_SZARRAY:
225         case MONO_TYPE_ARRAY:
226                 return TRUE;
227         case MONO_TYPE_GENERICINST:
228                 if (!mono_type_generic_inst_is_valuetype (t))
229                         return TRUE;
230                 return FALSE;
231         case MONO_TYPE_VALUETYPE:
232                 return FALSE;
233         }
234         return FALSE;
235 }
236
237 GList *
238 mono_arch_get_allocatable_int_vars (MonoCompile *cfg)
239 {
240         GList *vars = NULL;
241         int i;
242
243         for (i = 0; i < cfg->num_varinfo; i++) {
244                 MonoInst *ins = cfg->varinfo [i];
245                 MonoMethodVar *vmv = MONO_VARINFO (cfg, i);
246
247                 /* unused vars */
248                 if (vmv->range.first_use.abs_pos >= vmv->range.last_use.abs_pos)
249                         continue;
250
251                 if (ins->flags & (MONO_INST_VOLATILE|MONO_INST_INDIRECT) || (ins->opcode != OP_LOCAL && ins->opcode != OP_ARG))
252                         continue;
253
254                 /* we can only allocate 32 bit values */
255                 if (is_regsize_var (ins->inst_vtype)) {
256                         g_assert (MONO_VARINFO (cfg, i)->reg == -1);
257                         g_assert (i == vmv->idx);
258                         vars = mono_varlist_insert_sorted (cfg, vars, vmv, FALSE);
259                 }
260         }
261
262         return vars;
263 }
264
265 #define USE_EXTRA_TEMPS 0
266
267 GList *
268 mono_arch_get_global_int_regs (MonoCompile *cfg)
269 {
270         GList *regs = NULL;
271         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V1));
272         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V2));
273         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V3));
274         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V4));
275         regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V5));
276         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V6));*/
277         /*regs = g_list_prepend (regs, GUINT_TO_POINTER (ARMREG_V7));*/
278
279         return regs;
280 }
281
282 /*
283  * mono_arch_regalloc_cost:
284  *
285  *  Return the cost, in number of memory references, of the action of 
286  * allocating the variable VMV into a register during global register
287  * allocation.
288  */
289 guint32
290 mono_arch_regalloc_cost (MonoCompile *cfg, MonoMethodVar *vmv)
291 {
292         /* FIXME: */
293         return 2;
294 }
295
296 void
297 mono_arch_flush_icache (guint8 *code, gint size)
298 {
299         __asm __volatile ("mov r0, %0\n"
300                         "mov r1, %1\n"
301                         "mov r2, %2\n"
302                         "swi 0x9f0002       @ sys_cacheflush"
303                         : /* no outputs */
304                         : "r" (code), "r" (code + size), "r" (0)
305                         : "r0", "r1", "r3" );
306
307 }
308
309 #define NOT_IMPLEMENTED(x) \
310                 g_error ("FIXME: %s is not yet implemented. (trampoline)", x);
311
312 enum {
313         RegTypeGeneral,
314         RegTypeBase,
315         RegTypeFP,
316         RegTypeStructByVal,
317         RegTypeStructByAddr
318 };
319
320 typedef struct {
321         gint32  offset;
322         guint16 vtsize; /* in param area */
323         guint8  reg;
324         guint8  regtype : 4; /* 0 general, 1 basereg, 2 floating point register, see RegType* */
325         guint8  size    : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */
326 } ArgInfo;
327
328 typedef struct {
329         int nargs;
330         guint32 stack_usage;
331         guint32 struct_ret;
332         ArgInfo ret;
333         ArgInfo sig_cookie;
334         ArgInfo args [1];
335 } CallInfo;
336
337 #define DEBUG(a)
338
339 static void inline
340 add_general (guint *gr, guint *stack_size, ArgInfo *ainfo, gboolean simple)
341 {
342         if (simple) {
343                 if (*gr > ARMREG_R3) {
344                         ainfo->offset = *stack_size;
345                         ainfo->reg = ARMREG_SP; /* in the caller */
346                         ainfo->regtype = RegTypeBase;
347                         *stack_size += 4;
348                 } else {
349                         ainfo->reg = *gr;
350                 }
351         } else {
352                 if (*gr > ARMREG_R2) {
353                         /**stack_size += 7;
354                         *stack_size &= ~7;*/
355                         ainfo->offset = *stack_size;
356                         ainfo->reg = ARMREG_SP; /* in the caller */
357                         ainfo->regtype = RegTypeBase;
358                         *stack_size += 8;
359                 } else {
360                         /*if ((*gr) & 1)
361                                 (*gr) ++;*/
362                         ainfo->reg = *gr;
363                 }
364                 (*gr) ++;
365         }
366         (*gr) ++;
367 }
368
369 static CallInfo*
370 calculate_sizes (MonoMethodSignature *sig, gboolean is_pinvoke)
371 {
372         guint i, gr;
373         int n = sig->hasthis + sig->param_count;
374         guint32 simpletype;
375         guint32 stack_size = 0;
376         CallInfo *cinfo = g_malloc0 (sizeof (CallInfo) + sizeof (ArgInfo) * n);
377
378         gr = ARMREG_R0;
379
380         /* FIXME: handle returning a struct */
381         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
382                 add_general (&gr, &stack_size, &cinfo->ret, TRUE);
383                 cinfo->struct_ret = ARMREG_R0;
384         }
385
386         n = 0;
387         if (sig->hasthis) {
388                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
389                 n++;
390         }
391         DEBUG(printf("params: %d\n", sig->param_count));
392         for (i = 0; i < sig->param_count; ++i) {
393                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
394                         /* Prevent implicit arguments and sig_cookie from
395                            being passed in registers */
396                         gr = ARMREG_R3 + 1;
397                         /* Emit the signature cookie just before the implicit arguments */
398                         add_general (&gr, &stack_size, &cinfo->sig_cookie, TRUE);
399                 }
400                 DEBUG(printf("param %d: ", i));
401                 if (sig->params [i]->byref) {
402                         DEBUG(printf("byref\n"));
403                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
404                         n++;
405                         continue;
406                 }
407                 simpletype = mono_type_get_underlying_type (sig->params [i])->type;
408                 switch (simpletype) {
409                 case MONO_TYPE_BOOLEAN:
410                 case MONO_TYPE_I1:
411                 case MONO_TYPE_U1:
412                         cinfo->args [n].size = 1;
413                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
414                         n++;
415                         break;
416                 case MONO_TYPE_CHAR:
417                 case MONO_TYPE_I2:
418                 case MONO_TYPE_U2:
419                         cinfo->args [n].size = 2;
420                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
421                         n++;
422                         break;
423                 case MONO_TYPE_I4:
424                 case MONO_TYPE_U4:
425                         cinfo->args [n].size = 4;
426                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
427                         n++;
428                         break;
429                 case MONO_TYPE_I:
430                 case MONO_TYPE_U:
431                 case MONO_TYPE_PTR:
432                 case MONO_TYPE_FNPTR:
433                 case MONO_TYPE_CLASS:
434                 case MONO_TYPE_OBJECT:
435                 case MONO_TYPE_STRING:
436                 case MONO_TYPE_SZARRAY:
437                 case MONO_TYPE_ARRAY:
438                 case MONO_TYPE_R4:
439                         cinfo->args [n].size = sizeof (gpointer);
440                         add_general (&gr, &stack_size, cinfo->args + n, TRUE);
441                         n++;
442                         break;
443                 case MONO_TYPE_GENERICINST:
444                         if (!mono_type_generic_inst_is_valuetype (sig->params [i])) {
445                                 cinfo->args [n].size = sizeof (gpointer);
446                                 add_general (&gr, &stack_size, cinfo->args + n, TRUE);
447                                 n++;
448                                 break;
449                         }
450                         /* Fall through */
451                 case MONO_TYPE_TYPEDBYREF:
452                 case MONO_TYPE_VALUETYPE: {
453                         gint size;
454                         int align_size;
455                         int nwords;
456
457                         if (simpletype == MONO_TYPE_TYPEDBYREF) {
458                                 size = sizeof (MonoTypedRef);
459                         } else {
460                                 MonoClass *klass = mono_class_from_mono_type (sig->params [i]);
461                                 if (is_pinvoke)
462                                         size = mono_class_native_size (klass, NULL);
463                                 else
464                                         size = mono_class_value_size (klass, NULL);
465                         }
466                         DEBUG(printf ("load %d bytes struct\n",
467                                       mono_class_native_size (sig->params [i]->data.klass, NULL)));
468                         align_size = size;
469                         nwords = 0;
470                         align_size += (sizeof (gpointer) - 1);
471                         align_size &= ~(sizeof (gpointer) - 1);
472                         nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
473                         cinfo->args [n].regtype = RegTypeStructByVal;
474                         /* FIXME: align gr and stack_size if needed */
475                         if (gr > ARMREG_R3) {
476                                 cinfo->args [n].size = 0;
477                                 cinfo->args [n].vtsize = nwords;
478                         } else {
479                                 int rest = ARMREG_R3 - gr + 1;
480                                 int n_in_regs = rest >= nwords? nwords: rest;
481                                 cinfo->args [n].size = n_in_regs;
482                                 cinfo->args [n].vtsize = nwords - n_in_regs;
483                                 cinfo->args [n].reg = gr;
484                                 gr += n_in_regs;
485                         }
486                         cinfo->args [n].offset = stack_size;
487                         /*g_print ("offset for arg %d at %d\n", n, stack_size);*/
488                         stack_size += nwords * sizeof (gpointer);
489                         n++;
490                         break;
491                 }
492                 case MONO_TYPE_U8:
493                 case MONO_TYPE_I8:
494                 case MONO_TYPE_R8:
495                         cinfo->args [n].size = 8;
496                         add_general (&gr, &stack_size, cinfo->args + n, FALSE);
497                         n++;
498                         break;
499                 default:
500                         g_error ("Can't trampoline 0x%x", sig->params [i]->type);
501                 }
502         }
503
504         {
505                 simpletype = mono_type_get_underlying_type (sig->ret)->type;
506                 switch (simpletype) {
507                 case MONO_TYPE_BOOLEAN:
508                 case MONO_TYPE_I1:
509                 case MONO_TYPE_U1:
510                 case MONO_TYPE_I2:
511                 case MONO_TYPE_U2:
512                 case MONO_TYPE_CHAR:
513                 case MONO_TYPE_I4:
514                 case MONO_TYPE_U4:
515                 case MONO_TYPE_I:
516                 case MONO_TYPE_U:
517                 case MONO_TYPE_PTR:
518                 case MONO_TYPE_FNPTR:
519                 case MONO_TYPE_CLASS:
520                 case MONO_TYPE_OBJECT:
521                 case MONO_TYPE_SZARRAY:
522                 case MONO_TYPE_ARRAY:
523                 case MONO_TYPE_STRING:
524                         cinfo->ret.reg = ARMREG_R0;
525                         break;
526                 case MONO_TYPE_U8:
527                 case MONO_TYPE_I8:
528                         cinfo->ret.reg = ARMREG_R0;
529                         break;
530                 case MONO_TYPE_R4:
531                 case MONO_TYPE_R8:
532                         cinfo->ret.reg = ARMREG_R0;
533                         /* FIXME: cinfo->ret.reg = ???;
534                         cinfo->ret.regtype = RegTypeFP;*/
535                         break;
536                 case MONO_TYPE_GENERICINST:
537                         if (!mono_type_generic_inst_is_valuetype (sig->ret)) {
538                                 cinfo->ret.reg = ARMREG_R0;
539                                 break;
540                         }
541                         break;
542                 case MONO_TYPE_VALUETYPE:
543                         break;
544                 case MONO_TYPE_TYPEDBYREF:
545                 case MONO_TYPE_VOID:
546                         break;
547                 default:
548                         g_error ("Can't handle as return value 0x%x", sig->ret->type);
549                 }
550         }
551
552         /* align stack size to 8 */
553         DEBUG (printf ("      stack size: %d (%d)\n", (stack_size + 15) & ~15, stack_size));
554         stack_size = (stack_size + 7) & ~7;
555
556         cinfo->stack_usage = stack_size;
557         return cinfo;
558 }
559
560
561 /*
562  * Set var information according to the calling convention. arm version.
563  * The locals var stuff should most likely be split in another method.
564  */
565 void
566 mono_arch_allocate_vars (MonoCompile *m)
567 {
568         MonoMethodSignature *sig;
569         MonoMethodHeader *header;
570         MonoInst *inst;
571         int i, offset, size, align, curinst;
572         int frame_reg = ARMREG_FP;
573
574         /* FIXME: this will change when we use FP as gcc does */
575         m->flags |= MONO_CFG_HAS_SPILLUP;
576
577         /* allow room for the vararg method args: void* and long/double */
578         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
579                 m->param_area = MAX (m->param_area, sizeof (gpointer)*8);
580
581         header = mono_method_get_header (m->method);
582
583         /* 
584          * We use the frame register also for any method that has
585          * exception clauses. This way, when the handlers are called,
586          * the code will reference local variables using the frame reg instead of
587          * the stack pointer: if we had to restore the stack pointer, we'd
588          * corrupt the method frames that are already on the stack (since
589          * filters get called before stack unwinding happens) when the filter
590          * code would call any method (this also applies to finally etc.).
591          */ 
592         if ((m->flags & MONO_CFG_HAS_ALLOCA) || header->num_clauses)
593                 frame_reg = ARMREG_FP;
594         m->frame_reg = frame_reg;
595         if (frame_reg != ARMREG_SP) {
596                 m->used_int_regs |= 1 << frame_reg;
597         }
598
599         sig = mono_method_signature (m->method);
600         
601         offset = 0;
602         curinst = 0;
603         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
604                 m->ret->opcode = OP_REGVAR;
605                 m->ret->inst_c0 = ARMREG_R0;
606         } else {
607                 /* FIXME: handle long and FP values */
608                 switch (mono_type_get_underlying_type (sig->ret)->type) {
609                 case MONO_TYPE_VOID:
610                         break;
611                 default:
612                         m->ret->opcode = OP_REGVAR;
613                         m->ret->inst_c0 = ARMREG_R0;
614                         break;
615                 }
616         }
617         /* local vars are at a positive offset from the stack pointer */
618         /* 
619          * also note that if the function uses alloca, we use FP
620          * to point at the local variables.
621          */
622         offset = 0; /* linkage area */
623         /* align the offset to 16 bytes: not sure this is needed here  */
624         //offset += 8 - 1;
625         //offset &= ~(8 - 1);
626
627         /* add parameter area size for called functions */
628         offset += m->param_area;
629         offset += 8 - 1;
630         offset &= ~(8 - 1);
631         if (m->flags & MONO_CFG_HAS_FPOUT)
632                 offset += 8;
633
634         /* allow room to save the return value */
635         if (mono_jit_trace_calls != NULL && mono_trace_eval (m->method))
636                 offset += 8;
637
638         /* the MonoLMF structure is stored just below the stack pointer */
639
640         if (sig->call_convention == MONO_CALL_VARARG) {
641                 m->sig_cookie = 0;
642         }
643
644         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
645                 inst = m->ret;
646                 offset += sizeof(gpointer) - 1;
647                 offset &= ~(sizeof(gpointer) - 1);
648                 inst->inst_offset = offset;
649                 inst->opcode = OP_REGOFFSET;
650                 inst->inst_basereg = frame_reg;
651                 offset += sizeof(gpointer);
652                 if (sig->call_convention == MONO_CALL_VARARG)
653                         m->sig_cookie += sizeof (gpointer);
654         }
655
656         curinst = m->locals_start;
657         for (i = curinst; i < m->num_varinfo; ++i) {
658                 inst = m->varinfo [i];
659                 if ((inst->flags & MONO_INST_IS_DEAD) || inst->opcode == OP_REGVAR)
660                         continue;
661
662                 /* inst->backend.is_pinvoke indicates native sized value types, this is used by the
663                 * pinvoke wrappers when they call functions returning structure */
664                 if (inst->backend.is_pinvoke && MONO_TYPE_ISSTRUCT (inst->inst_vtype) && inst->inst_vtype->type != MONO_TYPE_TYPEDBYREF)
665                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), &align);
666                 else
667                         size = mono_type_size (inst->inst_vtype, &align);
668
669                 /* FIXME: if a structure is misaligned, our memcpy doesn't work,
670                  * since it loads/stores misaligned words, which don't do the right thing.
671                  */
672                 if (align < 4 && size >= 4)
673                         align = 4;
674                 offset += align - 1;
675                 offset &= ~(align - 1);
676                 inst->inst_offset = offset;
677                 inst->opcode = OP_REGOFFSET;
678                 inst->inst_basereg = frame_reg;
679                 offset += size;
680                 //g_print ("allocating local %d to %d\n", i, inst->inst_offset);
681         }
682
683         curinst = 0;
684         if (sig->hasthis) {
685                 inst = m->varinfo [curinst];
686                 if (inst->opcode != OP_REGVAR) {
687                         inst->opcode = OP_REGOFFSET;
688                         inst->inst_basereg = frame_reg;
689                         offset += sizeof (gpointer) - 1;
690                         offset &= ~(sizeof (gpointer) - 1);
691                         inst->inst_offset = offset;
692                         offset += sizeof (gpointer);
693                         if (sig->call_convention == MONO_CALL_VARARG)
694                                 m->sig_cookie += sizeof (gpointer);
695                 }
696                 curinst++;
697         }
698
699         for (i = 0; i < sig->param_count; ++i) {
700                 inst = m->varinfo [curinst];
701                 if (inst->opcode != OP_REGVAR) {
702                         inst->opcode = OP_REGOFFSET;
703                         inst->inst_basereg = frame_reg;
704                         size = mono_type_size (sig->params [i], &align);
705                         /* FIXME: if a structure is misaligned, our memcpy doesn't work,
706                          * since it loads/stores misaligned words, which don't do the right thing.
707                          */
708                         if (align < 4 && size >= 4)
709                                 align = 4;
710                         offset += align - 1;
711                         offset &= ~(align - 1);
712                         inst->inst_offset = offset;
713                         offset += size;
714                         if ((sig->call_convention == MONO_CALL_VARARG) && (i < sig->sentinelpos)) 
715                                 m->sig_cookie += size;
716                 }
717                 curinst++;
718         }
719
720         /* align the offset to 8 bytes */
721         offset += 8 - 1;
722         offset &= ~(8 - 1);
723
724         /* change sign? */
725         m->stack_offset = offset;
726
727 }
728
729 /* Fixme: we need an alignment solution for enter_method and mono_arch_call_opcode,
730  * currently alignment in mono_arch_call_opcode is computed without arch_get_argument_info 
731  */
732
733 /* 
734  * take the arguments and generate the arch-specific
735  * instructions to properly call the function in call.
736  * This includes pushing, moving arguments to the right register
737  * etc.
738  * Issue: who does the spilling if needed, and when?
739  */
740 MonoCallInst*
741 mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call, int is_virtual) {
742         MonoInst *arg, *in;
743         MonoMethodSignature *sig;
744         int i, n;
745         CallInfo *cinfo;
746         ArgInfo *ainfo;
747
748         sig = call->signature;
749         n = sig->param_count + sig->hasthis;
750         
751         cinfo = calculate_sizes (sig, sig->pinvoke);
752         if (cinfo->struct_ret)
753                 call->used_iregs |= 1 << cinfo->struct_ret;
754
755         for (i = 0; i < n; ++i) {
756                 ainfo = cinfo->args + i;
757                 if ((sig->call_convention == MONO_CALL_VARARG) && (i == sig->sentinelpos)) {
758                         MonoInst *sig_arg;
759                         cfg->disable_aot = TRUE;
760                                 
761                         MONO_INST_NEW (cfg, sig_arg, OP_ICONST);
762                         sig_arg->inst_p0 = call->signature;
763                         
764                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
765                         arg->inst_imm = cinfo->sig_cookie.offset;
766                         arg->inst_left = sig_arg;
767                         
768                         /* prepend, so they get reversed */
769                         arg->next = call->out_args;
770                         call->out_args = arg;
771                 }
772                 if (is_virtual && i == 0) {
773                         /* the argument will be attached to the call instrucion */
774                         in = call->args [i];
775                         call->used_iregs |= 1 << ainfo->reg;
776                 } else {
777                         MONO_INST_NEW (cfg, arg, OP_OUTARG);
778                         in = call->args [i];
779                         arg->cil_code = in->cil_code;
780                         arg->inst_left = in;
781                         arg->inst_right = (MonoInst*)call;
782                         arg->type = in->type;
783                         /* prepend, we'll need to reverse them later */
784                         arg->next = call->out_args;
785                         call->out_args = arg;
786                         if (ainfo->regtype == RegTypeGeneral) {
787                                 arg->backend.reg3 = ainfo->reg;
788                                 call->used_iregs |= 1 << ainfo->reg;
789                                 if (arg->type == STACK_I8)
790                                         call->used_iregs |= 1 << (ainfo->reg + 1);
791                                 if (arg->type == STACK_R8) {
792                                         if (ainfo->size == 4) {
793                                                 arg->opcode = OP_OUTARG_R4;
794                                         } else {
795                                                 call->used_iregs |= 1 << (ainfo->reg + 1);
796                                         }
797                                         cfg->flags |= MONO_CFG_HAS_FPOUT;
798                                 }
799                         } else if (ainfo->regtype == RegTypeStructByAddr) {
800                                 /* FIXME: where si the data allocated? */
801                                 arg->backend.reg3 = ainfo->reg;
802                                 call->used_iregs |= 1 << ainfo->reg;
803                                 g_assert_not_reached ();
804                         } else if (ainfo->regtype == RegTypeStructByVal) {
805                                 int cur_reg;
806                                 /* mark the used regs */
807                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
808                                         call->used_iregs |= 1 << (ainfo->reg + cur_reg);
809                                 }
810                                 arg->opcode = OP_OUTARG_VT;
811                                 /* vtsize and offset have just 12 bits of encoding in number of words */
812                                 g_assert (((ainfo->vtsize | (ainfo->offset / 4)) & 0xfffff000) == 0);
813                                 arg->backend.arg_info = ainfo->reg | (ainfo->size << 4) | (ainfo->vtsize << 8) | ((ainfo->offset / 4) << 20);
814                         } else if (ainfo->regtype == RegTypeBase) {
815                                 arg->opcode = OP_OUTARG_MEMBASE;
816                                 arg->backend.arg_info = (ainfo->offset << 8) | ainfo->size;
817                         } else if (ainfo->regtype == RegTypeFP) {
818                                 arg->backend.reg3 = ainfo->reg;
819                                 /* FPA args are passed in int regs */
820                                 call->used_iregs |= 1 << ainfo->reg;
821                                 if (ainfo->size == 8) {
822                                         arg->opcode = OP_OUTARG_R8;
823                                         call->used_iregs |= 1 << (ainfo->reg + 1);
824                                 } else {
825                                         arg->opcode = OP_OUTARG_R4;
826                                 }
827                                 cfg->flags |= MONO_CFG_HAS_FPOUT;
828                         } else {
829                                 g_assert_not_reached ();
830                         }
831                 }
832         }
833         /*
834          * Reverse the call->out_args list.
835          */
836         {
837                 MonoInst *prev = NULL, *list = call->out_args, *next;
838                 while (list) {
839                         next = list->next;
840                         list->next = prev;
841                         prev = list;
842                         list = next;
843                 }
844                 call->out_args = prev;
845         }
846         call->stack_usage = cinfo->stack_usage;
847         cfg->param_area = MAX (cfg->param_area, cinfo->stack_usage);
848         cfg->flags |= MONO_CFG_HAS_CALLS;
849         /* 
850          * should set more info in call, such as the stack space
851          * used by the args that needs to be added back to esp
852          */
853
854         g_free (cinfo);
855         return call;
856 }
857
858 /*
859  * Allow tracing to work with this interface (with an optional argument)
860  */
861
862 void*
863 mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
864 {
865         guchar *code = p;
866
867         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
868         ARM_MOV_REG_IMM8 (code, ARMREG_R1, 0); /* NULL ebp for now */
869         code = mono_arm_emit_load_imm (code, ARMREG_R2, (guint32)func);
870         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
871         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_R2);
872         return code;
873 }
874
875 enum {
876         SAVE_NONE,
877         SAVE_STRUCT,
878         SAVE_ONE,
879         SAVE_TWO,
880         SAVE_FP
881 };
882
883 void*
884 mono_arch_instrument_epilog (MonoCompile *cfg, void *func, void *p, gboolean enable_arguments)
885 {
886         guchar *code = p;
887         int save_mode = SAVE_NONE;
888         int offset;
889         MonoMethod *method = cfg->method;
890         int rtype = mono_type_get_underlying_type (mono_method_signature (method)->ret)->type;
891         int save_offset = cfg->param_area;
892         save_offset += 7;
893         save_offset &= ~7;
894         
895         offset = code - cfg->native_code;
896         /* we need about 16 instructions */
897         if (offset > (cfg->code_size - 16 * 4)) {
898                 cfg->code_size *= 2;
899                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
900                 code = cfg->native_code + offset;
901         }
902 handle_enum:
903         switch (rtype) {
904         case MONO_TYPE_VOID:
905                 /* special case string .ctor icall */
906                 if (strcmp (".ctor", method->name) && method->klass == mono_defaults.string_class)
907                         save_mode = SAVE_ONE;
908                 else
909                         save_mode = SAVE_NONE;
910                 break;
911         case MONO_TYPE_I8:
912         case MONO_TYPE_U8:
913                 save_mode = SAVE_TWO;
914                 break;
915         case MONO_TYPE_R4:
916         case MONO_TYPE_R8:
917                 save_mode = SAVE_FP;
918                 break;
919         case MONO_TYPE_VALUETYPE:
920                 save_mode = SAVE_STRUCT;
921                 break;
922         default:
923                 save_mode = SAVE_ONE;
924                 break;
925         }
926
927         switch (save_mode) {
928         case SAVE_TWO:
929                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
930                 ARM_STR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
931                 if (enable_arguments) {
932                         ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_R1);
933                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
934                 }
935                 break;
936         case SAVE_ONE:
937                 ARM_STR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
938                 if (enable_arguments) {
939                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
940                 }
941                 break;
942         case SAVE_FP:
943                 /* FIXME: what reg?  */
944                 if (enable_arguments) {
945                         /* FIXME: what reg?  */
946                 }
947                 break;
948         case SAVE_STRUCT:
949                 if (enable_arguments) {
950                         /* FIXME: get the actual address  */
951                         ARM_MOV_REG_REG (code, ARMREG_R1, ARMREG_R0);
952                 }
953                 break;
954         case SAVE_NONE:
955         default:
956                 break;
957         }
958
959         code = mono_arm_emit_load_imm (code, ARMREG_R0, (guint32)cfg->method);
960         code = mono_arm_emit_load_imm (code, ARMREG_IP, (guint32)func);
961         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
962         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
963
964         switch (save_mode) {
965         case SAVE_TWO:
966                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
967                 ARM_LDR_IMM (code, ARMREG_R1, cfg->frame_reg, save_offset + 4);
968                 break;
969         case SAVE_ONE:
970                 ARM_LDR_IMM (code, ARMREG_R0, cfg->frame_reg, save_offset);
971                 break;
972         case SAVE_FP:
973                 /* FIXME */
974                 break;
975         case SAVE_NONE:
976         default:
977                 break;
978         }
979
980         return code;
981 }
982
983 /*
984  * The immediate field for cond branches is big enough for all reasonable methods
985  */
986 #define EMIT_COND_BRANCH_FLAGS(ins,condcode) \
987 if (ins->flags & MONO_INST_BRLABEL) { \
988         if (0 && ins->inst_i0->inst_c0) { \
989                 ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_i0->inst_c0) & 0xffffff);    \
990         } else { \
991                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_LABEL, ins->inst_i0); \
992                 ARM_B_COND (code, (condcode), 0);       \
993         } \
994 } else { \
995         if (0 && ins->inst_true_bb->native_offset) { \
996                 ARM_B_COND (code, (condcode), (code - cfg->native_code + ins->inst_true_bb->native_offset) & 0xffffff); \
997         } else { \
998                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_true_bb); \
999                 ARM_B_COND (code, (condcode), 0);       \
1000         } \
1001 }
1002
1003 #define EMIT_COND_BRANCH(ins,cond) EMIT_COND_BRANCH_FLAGS(ins, branch_cc_table [(cond)])
1004
1005 /* emit an exception if condition is fail
1006  *
1007  * We assign the extra code used to throw the implicit exceptions
1008  * to cfg->bb_exit as far as the big branch handling is concerned
1009  */
1010 #define EMIT_COND_SYSTEM_EXCEPTION_FLAGS(condcode,exc_name)            \
1011         do {                                                        \
1012                 mono_add_patch_info (cfg, code - cfg->native_code,   \
1013                                     MONO_PATCH_INFO_EXC, exc_name);  \
1014                 ARM_BL_COND (code, (condcode), 0);      \
1015         } while (0); 
1016
1017 #define EMIT_COND_SYSTEM_EXCEPTION(cond,exc_name) EMIT_COND_SYSTEM_EXCEPTION_FLAGS(branch_cc_table [(cond)], (exc_name))
1018
1019 static void
1020 peephole_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1021 {
1022         MonoInst *ins, *last_ins = NULL;
1023         ins = bb->code;
1024
1025         while (ins) {
1026
1027                 switch (ins->opcode) {
1028                 case OP_MUL_IMM: 
1029                         /* remove unnecessary multiplication with 1 */
1030                         if (ins->inst_imm == 1) {
1031                                 if (ins->dreg != ins->sreg1) {
1032                                         ins->opcode = OP_MOVE;
1033                                 } else {
1034                                         last_ins->next = ins->next;                             
1035                                         ins = ins->next;                                
1036                                         continue;
1037                                 }
1038                         } else {
1039                                 int power2 = mono_is_power_of_two (ins->inst_imm);
1040                                 if (power2 > 0) {
1041                                         ins->opcode = OP_SHL_IMM;
1042                                         ins->inst_imm = power2;
1043                                 }
1044                         }
1045                         break;
1046                 case OP_LOAD_MEMBASE:
1047                 case OP_LOADI4_MEMBASE:
1048                         /* 
1049                          * OP_STORE_MEMBASE_REG reg, offset(basereg) 
1050                          * OP_LOAD_MEMBASE offset(basereg), reg
1051                          */
1052                         if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_REG 
1053                                          || last_ins->opcode == OP_STORE_MEMBASE_REG) &&
1054                             ins->inst_basereg == last_ins->inst_destbasereg &&
1055                             ins->inst_offset == last_ins->inst_offset) {
1056                                 if (ins->dreg == last_ins->sreg1) {
1057                                         last_ins->next = ins->next;                             
1058                                         ins = ins->next;                                
1059                                         continue;
1060                                 } else {
1061                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1062                                         ins->opcode = OP_MOVE;
1063                                         ins->sreg1 = last_ins->sreg1;
1064                                 }
1065
1066                         /* 
1067                          * Note: reg1 must be different from the basereg in the second load
1068                          * OP_LOAD_MEMBASE offset(basereg), reg1
1069                          * OP_LOAD_MEMBASE offset(basereg), reg2
1070                          * -->
1071                          * OP_LOAD_MEMBASE offset(basereg), reg1
1072                          * OP_MOVE reg1, reg2
1073                          */
1074                         } if (last_ins && (last_ins->opcode == OP_LOADI4_MEMBASE
1075                                            || last_ins->opcode == OP_LOAD_MEMBASE) &&
1076                               ins->inst_basereg != last_ins->dreg &&
1077                               ins->inst_basereg == last_ins->inst_basereg &&
1078                               ins->inst_offset == last_ins->inst_offset) {
1079
1080                                 if (ins->dreg == last_ins->dreg) {
1081                                         last_ins->next = ins->next;                             
1082                                         ins = ins->next;                                
1083                                         continue;
1084                                 } else {
1085                                         ins->opcode = OP_MOVE;
1086                                         ins->sreg1 = last_ins->dreg;
1087                                 }
1088
1089                                 //g_assert_not_reached ();
1090
1091 #if 0
1092                         /* 
1093                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1094                          * OP_LOAD_MEMBASE offset(basereg), reg
1095                          * -->
1096                          * OP_STORE_MEMBASE_IMM imm, offset(basereg) 
1097                          * OP_ICONST reg, imm
1098                          */
1099                         } else if (last_ins && (last_ins->opcode == OP_STOREI4_MEMBASE_IMM
1100                                                 || last_ins->opcode == OP_STORE_MEMBASE_IMM) &&
1101                                    ins->inst_basereg == last_ins->inst_destbasereg &&
1102                                    ins->inst_offset == last_ins->inst_offset) {
1103                                 //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1104                                 ins->opcode = OP_ICONST;
1105                                 ins->inst_c0 = last_ins->inst_imm;
1106                                 g_assert_not_reached (); // check this rule
1107 #endif
1108                         }
1109                         break;
1110                 case OP_LOADU1_MEMBASE:
1111                 case OP_LOADI1_MEMBASE:
1112                         if (last_ins && (last_ins->opcode == OP_STOREI1_MEMBASE_REG) &&
1113                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1114                                         ins->inst_offset == last_ins->inst_offset) {
1115                                 if (ins->dreg == last_ins->sreg1) {
1116                                         last_ins->next = ins->next;                             
1117                                         ins = ins->next;                                
1118                                         continue;
1119                                 } else {
1120                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1121                                         ins->opcode = OP_MOVE;
1122                                         ins->sreg1 = last_ins->sreg1;
1123                                 }
1124                         }
1125                         break;
1126                 case OP_LOADU2_MEMBASE:
1127                 case OP_LOADI2_MEMBASE:
1128                         if (last_ins && (last_ins->opcode == OP_STOREI2_MEMBASE_REG) &&
1129                                         ins->inst_basereg == last_ins->inst_destbasereg &&
1130                                         ins->inst_offset == last_ins->inst_offset) {
1131                                 if (ins->dreg == last_ins->sreg1) {
1132                                         last_ins->next = ins->next;                             
1133                                         ins = ins->next;                                
1134                                         continue;
1135                                 } else {
1136                                         //static int c = 0; printf ("MATCHX %s %d\n", cfg->method->name,c++);
1137                                         ins->opcode = OP_MOVE;
1138                                         ins->sreg1 = last_ins->sreg1;
1139                                 }
1140                         }
1141                         break;
1142                 case CEE_CONV_I4:
1143                 case CEE_CONV_U4:
1144                 case OP_MOVE:
1145                 case OP_SETREG:
1146                         ins->opcode = OP_MOVE;
1147                         /* 
1148                          * OP_MOVE reg, reg 
1149                          */
1150                         if (ins->dreg == ins->sreg1) {
1151                                 if (last_ins)
1152                                         last_ins->next = ins->next;                             
1153                                 ins = ins->next;
1154                                 continue;
1155                         }
1156                         /* 
1157                          * OP_MOVE sreg, dreg 
1158                          * OP_MOVE dreg, sreg
1159                          */
1160                         if (last_ins && last_ins->opcode == OP_MOVE &&
1161                             ins->sreg1 == last_ins->dreg &&
1162                             ins->dreg == last_ins->sreg1) {
1163                                 last_ins->next = ins->next;                             
1164                                 ins = ins->next;                                
1165                                 continue;
1166                         }
1167                         break;
1168                 }
1169                 last_ins = ins;
1170                 ins = ins->next;
1171         }
1172         bb->last_ins = last_ins;
1173 }
1174
1175 /* 
1176  * the branch_cc_table should maintain the order of these
1177  * opcodes.
1178 case CEE_BEQ:
1179 case CEE_BGE:
1180 case CEE_BGT:
1181 case CEE_BLE:
1182 case CEE_BLT:
1183 case CEE_BNE_UN:
1184 case CEE_BGE_UN:
1185 case CEE_BGT_UN:
1186 case CEE_BLE_UN:
1187 case CEE_BLT_UN:
1188  */
1189 static const guchar 
1190 branch_cc_table [] = {
1191         ARMCOND_EQ, 
1192         ARMCOND_GE, 
1193         ARMCOND_GT, 
1194         ARMCOND_LE,
1195         ARMCOND_LT, 
1196         
1197         ARMCOND_NE, 
1198         ARMCOND_HS, 
1199         ARMCOND_HI, 
1200         ARMCOND_LS,
1201         ARMCOND_LO
1202 };
1203
1204
1205 static void
1206 insert_after_ins (MonoBasicBlock *bb, MonoInst *ins, MonoInst *to_insert)
1207 {
1208         if (ins == NULL) {
1209                 ins = bb->code;
1210                 bb->code = to_insert;
1211                 to_insert->next = ins;
1212         } else {
1213                 to_insert->next = ins->next;
1214                 ins->next = to_insert;
1215         }
1216 }
1217
1218 #define NEW_INS(cfg,dest,op) do {       \
1219                 (dest) = mono_mempool_alloc0 ((cfg)->mempool, sizeof (MonoInst));       \
1220                 (dest)->opcode = (op);  \
1221                 insert_after_ins (bb, last_ins, (dest)); \
1222         } while (0)
1223
1224 static int
1225 map_to_reg_reg_op (int op)
1226 {
1227         switch (op) {
1228         case OP_ADD_IMM:
1229                 return CEE_ADD;
1230         case OP_SUB_IMM:
1231                 return CEE_SUB;
1232         case OP_AND_IMM:
1233                 return CEE_AND;
1234         case OP_COMPARE_IMM:
1235                 return OP_COMPARE;
1236         case OP_ADDCC_IMM:
1237                 return OP_ADDCC;
1238         case OP_ADC_IMM:
1239                 return OP_ADC;
1240         case OP_SUBCC_IMM:
1241                 return OP_SUBCC;
1242         case OP_SBB_IMM:
1243                 return OP_SBB;
1244         case OP_OR_IMM:
1245                 return CEE_OR;
1246         case OP_XOR_IMM:
1247                 return CEE_XOR;
1248         case OP_LOAD_MEMBASE:
1249                 return OP_LOAD_MEMINDEX;
1250         case OP_LOADI4_MEMBASE:
1251                 return OP_LOADI4_MEMINDEX;
1252         case OP_LOADU4_MEMBASE:
1253                 return OP_LOADU4_MEMINDEX;
1254         case OP_LOADU1_MEMBASE:
1255                 return OP_LOADU1_MEMINDEX;
1256         case OP_LOADI2_MEMBASE:
1257                 return OP_LOADI2_MEMINDEX;
1258         case OP_LOADU2_MEMBASE:
1259                 return OP_LOADU2_MEMINDEX;
1260         case OP_LOADI1_MEMBASE:
1261                 return OP_LOADI1_MEMINDEX;
1262         case OP_STOREI1_MEMBASE_REG:
1263                 return OP_STOREI1_MEMINDEX;
1264         case OP_STOREI2_MEMBASE_REG:
1265                 return OP_STOREI2_MEMINDEX;
1266         case OP_STOREI4_MEMBASE_REG:
1267                 return OP_STOREI4_MEMINDEX;
1268         case OP_STORE_MEMBASE_REG:
1269                 return OP_STORE_MEMINDEX;
1270         case OP_STORER4_MEMBASE_REG:
1271                 return OP_STORER4_MEMINDEX;
1272         case OP_STORER8_MEMBASE_REG:
1273                 return OP_STORER8_MEMINDEX;
1274         case OP_STORE_MEMBASE_IMM:
1275                 return OP_STORE_MEMBASE_REG;
1276         case OP_STOREI1_MEMBASE_IMM:
1277                 return OP_STOREI1_MEMBASE_REG;
1278         case OP_STOREI2_MEMBASE_IMM:
1279                 return OP_STOREI2_MEMBASE_REG;
1280         case OP_STOREI4_MEMBASE_IMM:
1281                 return OP_STOREI4_MEMBASE_REG;
1282         }
1283         g_assert_not_reached ();
1284 }
1285
1286 /*
1287  * Remove from the instruction list the instructions that can't be
1288  * represented with very simple instructions with no register
1289  * requirements.
1290  */
1291 static void
1292 mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb)
1293 {
1294         MonoInst *ins, *next, *temp, *last_ins = NULL;
1295         int rot_amount, imm8, low_imm;
1296
1297         /* setup the virtual reg allocator */
1298         if (bb->max_ireg > cfg->rs->next_vireg)
1299                 cfg->rs->next_vireg = bb->max_ireg;
1300
1301         ins = bb->code;
1302         while (ins) {
1303 loop_start:
1304                 switch (ins->opcode) {
1305                 case OP_ADD_IMM:
1306                 case OP_SUB_IMM:
1307                 case OP_AND_IMM:
1308                 case OP_COMPARE_IMM:
1309                 case OP_ADDCC_IMM:
1310                 case OP_ADC_IMM:
1311                 case OP_SUBCC_IMM:
1312                 case OP_SBB_IMM:
1313                 case OP_OR_IMM:
1314                 case OP_XOR_IMM:
1315                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount)) < 0) {
1316                                 NEW_INS (cfg, temp, OP_ICONST);
1317                                 temp->inst_c0 = ins->inst_imm;
1318                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1319                                 ins->sreg2 = temp->dreg;
1320                                 ins->opcode = map_to_reg_reg_op (ins->opcode);
1321                         }
1322                         break;
1323                 case OP_MUL_IMM:
1324                         if (ins->inst_imm == 1) {
1325                                 ins->opcode = OP_MOVE;
1326                                 break;
1327                         }
1328                         if (ins->inst_imm == 0) {
1329                                 ins->opcode = OP_ICONST;
1330                                 ins->inst_c0 = 0;
1331                                 break;
1332                         }
1333                         imm8 = mono_is_power_of_two (ins->inst_imm);
1334                         if (imm8 > 0) {
1335                                 ins->opcode = OP_SHL_IMM;
1336                                 ins->inst_imm = imm8;
1337                                 break;
1338                         }
1339                         NEW_INS (cfg, temp, OP_ICONST);
1340                         temp->inst_c0 = ins->inst_imm;
1341                         temp->dreg = mono_regstate_next_int (cfg->rs);
1342                         ins->sreg2 = temp->dreg;
1343                         ins->opcode = CEE_MUL;
1344                         break;
1345                 case OP_LOAD_MEMBASE:
1346                 case OP_LOADI4_MEMBASE:
1347                 case OP_LOADU4_MEMBASE:
1348                 case OP_LOADU1_MEMBASE:
1349                         /* we can do two things: load the immed in a register
1350                          * and use an indexed load, or see if the immed can be
1351                          * represented as an ad_imm + a load with a smaller offset
1352                          * that fits. We just do the first for now, optimize later.
1353                          */
1354                         if (arm_is_imm12 (ins->inst_offset))
1355                                 break;
1356                         NEW_INS (cfg, temp, OP_ICONST);
1357                         temp->inst_c0 = ins->inst_offset;
1358                         temp->dreg = mono_regstate_next_int (cfg->rs);
1359                         ins->sreg2 = temp->dreg;
1360                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1361                         break;
1362                 case OP_LOADI2_MEMBASE:
1363                 case OP_LOADU2_MEMBASE:
1364                 case OP_LOADI1_MEMBASE:
1365                         if (arm_is_imm8 (ins->inst_offset))
1366                                 break;
1367                         NEW_INS (cfg, temp, OP_ICONST);
1368                         temp->inst_c0 = ins->inst_offset;
1369                         temp->dreg = mono_regstate_next_int (cfg->rs);
1370                         ins->sreg2 = temp->dreg;
1371                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1372                         break;
1373                 case OP_LOADR4_MEMBASE:
1374                 case OP_LOADR8_MEMBASE:
1375                         if (arm_is_fpimm8 (ins->inst_offset))
1376                                 break;
1377                         low_imm = ins->inst_offset & 0x1ff;
1378                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~0x1ff, &rot_amount)) >= 0) {
1379                                 NEW_INS (cfg, temp, OP_ADD_IMM);
1380                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
1381                                 temp->sreg1 = ins->inst_basereg;
1382                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1383                                 ins->inst_basereg = temp->dreg;
1384                                 ins->inst_offset = low_imm;
1385                                 break;
1386                         }
1387                         /* FPA doesn't have indexed load instructions */
1388                         g_assert_not_reached ();
1389                         break;
1390                 case OP_STORE_MEMBASE_REG:
1391                 case OP_STOREI4_MEMBASE_REG:
1392                 case OP_STOREI1_MEMBASE_REG:
1393                         if (arm_is_imm12 (ins->inst_offset))
1394                                 break;
1395                         NEW_INS (cfg, temp, OP_ICONST);
1396                         temp->inst_c0 = ins->inst_offset;
1397                         temp->dreg = mono_regstate_next_int (cfg->rs);
1398                         ins->sreg2 = temp->dreg;
1399                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1400                         break;
1401                 case OP_STOREI2_MEMBASE_REG:
1402                         if (arm_is_imm8 (ins->inst_offset))
1403                                 break;
1404                         NEW_INS (cfg, temp, OP_ICONST);
1405                         temp->inst_c0 = ins->inst_offset;
1406                         temp->dreg = mono_regstate_next_int (cfg->rs);
1407                         ins->sreg2 = temp->dreg;
1408                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1409                         break;
1410                 case OP_STORER4_MEMBASE_REG:
1411                 case OP_STORER8_MEMBASE_REG:
1412                         if (arm_is_fpimm8 (ins->inst_offset))
1413                                 break;
1414                         low_imm = ins->inst_offset & 0x1ff;
1415                         if ((imm8 = mono_arm_is_rotated_imm8 (ins->inst_offset & ~ 0x1ff, &rot_amount)) >= 0 && arm_is_fpimm8 (low_imm)) {
1416                                 NEW_INS (cfg, temp, OP_ADD_IMM);
1417                                 temp->inst_imm = ins->inst_offset & ~0x1ff;
1418                                 temp->sreg1 = ins->inst_destbasereg;
1419                                 temp->dreg = mono_regstate_next_int (cfg->rs);
1420                                 ins->inst_destbasereg = temp->dreg;
1421                                 ins->inst_offset = low_imm;
1422                                 break;
1423                         }
1424                         /*g_print ("fail with: %d (%d, %d)\n", ins->inst_offset, ins->inst_offset & ~0x1ff, low_imm);*/
1425                         /* FPA doesn't have indexed store instructions */
1426                         g_assert_not_reached ();
1427                         break;
1428                 case OP_STORE_MEMBASE_IMM:
1429                 case OP_STOREI1_MEMBASE_IMM:
1430                 case OP_STOREI2_MEMBASE_IMM:
1431                 case OP_STOREI4_MEMBASE_IMM:
1432                         NEW_INS (cfg, temp, OP_ICONST);
1433                         temp->inst_c0 = ins->inst_imm;
1434                         temp->dreg = mono_regstate_next_int (cfg->rs);
1435                         ins->sreg1 = temp->dreg;
1436                         ins->opcode = map_to_reg_reg_op (ins->opcode);
1437                         last_ins = temp;
1438                         goto loop_start; /* make it handle the possibly big ins->inst_offset */
1439                 }
1440                 last_ins = ins;
1441                 ins = ins->next;
1442         }
1443         bb->last_ins = last_ins;
1444         bb->max_ireg = cfg->rs->next_vireg;
1445
1446 }
1447
1448 void
1449 mono_arch_local_regalloc (MonoCompile *cfg, MonoBasicBlock *bb)
1450 {
1451         if (!bb->code)
1452                 return;
1453         mono_arch_lowering_pass (cfg, bb);
1454         mono_local_regalloc (cfg, bb);
1455 }
1456
1457 static guchar*
1458 emit_float_to_int (MonoCompile *cfg, guchar *code, int dreg, int sreg, int size, gboolean is_signed)
1459 {
1460         /* sreg is a float, dreg is an integer reg  */
1461         ARM_FIXZ (code, dreg, sreg);
1462         if (!is_signed) {
1463                 if (size == 1)
1464                         ARM_AND_REG_IMM8 (code, dreg, dreg, 0xff);
1465                 else if (size == 2) {
1466                         ARM_SHL_IMM (code, dreg, dreg, 16);
1467                         ARM_SHR_IMM (code, dreg, dreg, 16);
1468                 }
1469         } else {
1470                 if (size == 1) {
1471                         ARM_SHL_IMM (code, dreg, dreg, 24);
1472                         ARM_SAR_IMM (code, dreg, dreg, 24);
1473                 } else if (size == 2) {
1474                         ARM_SHL_IMM (code, dreg, dreg, 16);
1475                         ARM_SAR_IMM (code, dreg, dreg, 16);
1476                 }
1477         }
1478         return code;
1479 }
1480
1481 typedef struct {
1482         guchar *code;
1483         const guchar *target;
1484         int absolute;
1485         int found;
1486 } PatchData;
1487
1488 #define is_call_imm(diff) ((gint)(diff) >= -33554432 && (gint)(diff) <= 33554431)
1489
1490 static int
1491 search_thunk_slot (void *data, int csize, int bsize, void *user_data) {
1492         PatchData *pdata = (PatchData*)user_data;
1493         guchar *code = data;
1494         guint32 *thunks = data;
1495         guint32 *endthunks = (guint32*)(code + bsize);
1496         int i, count = 0;
1497         int difflow, diffhigh;
1498
1499         /* always ensure a call from pdata->code can reach to the thunks without further thunks */
1500         difflow = (char*)pdata->code - (char*)thunks;
1501         diffhigh = (char*)pdata->code - (char*)endthunks;
1502         if (!((is_call_imm (thunks) && is_call_imm (endthunks)) || (is_call_imm (difflow) && is_call_imm (diffhigh))))
1503                 return 0;
1504
1505         /*
1506          * The thunk is composed of 3 words:
1507          * load constant from thunks [2] into ARM_IP
1508          * bx to ARM_IP
1509          * address constant
1510          * Note that the LR register is already setup
1511          */
1512         //g_print ("thunk nentries: %d\n", ((char*)endthunks - (char*)thunks)/16);
1513         if ((pdata->found == 2) || (pdata->code >= code && pdata->code <= code + csize)) {
1514                 while (thunks < endthunks) {
1515                         //g_print ("looking for target: %p at %p (%08x-%08x)\n", pdata->target, thunks, thunks [0], thunks [1]);
1516                         if (thunks [2] == (guint32)pdata->target) {
1517                                 arm_patch (pdata->code, (guchar*)thunks);
1518                                 mono_arch_flush_icache (pdata->code, 4);
1519                                 pdata->found = 1;
1520                                 return 1;
1521                         } else if ((thunks [0] == 0) && (thunks [1] == 0) && (thunks [2] == 0)) {
1522                                 /* found a free slot instead: emit thunk */
1523                                 code = (guchar*)thunks;
1524                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
1525                                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
1526                                 thunks [2] = (guint32)pdata->target;
1527                                 mono_arch_flush_icache ((guchar*)thunks, 12);
1528
1529                                 arm_patch (pdata->code, (guchar*)thunks);
1530                                 mono_arch_flush_icache (pdata->code, 4);
1531                                 pdata->found = 1;
1532                                 return 1;
1533                         }
1534                         /* skip 12 bytes, the size of the thunk */
1535                         thunks += 3;
1536                         count++;
1537                 }
1538                 //g_print ("failed thunk lookup for %p from %p at %p (%d entries)\n", pdata->target, pdata->code, data, count);
1539         }
1540         return 0;
1541 }
1542
1543 static void
1544 handle_thunk (int absolute, guchar *code, const guchar *target) {
1545         MonoDomain *domain = mono_domain_get ();
1546         PatchData pdata;
1547
1548         pdata.code = code;
1549         pdata.target = target;
1550         pdata.absolute = absolute;
1551         pdata.found = 0;
1552
1553         mono_domain_lock (domain);
1554         mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1555
1556         if (!pdata.found) {
1557                 /* this uses the first available slot */
1558                 pdata.found = 2;
1559                 mono_code_manager_foreach (domain->code_mp, search_thunk_slot, &pdata);
1560         }
1561         mono_domain_unlock (domain);
1562
1563         if (pdata.found != 1)
1564                 g_print ("thunk failed for %p from %p\n", target, code);
1565         g_assert (pdata.found == 1);
1566 }
1567
1568 void
1569 arm_patch (guchar *code, const guchar *target)
1570 {
1571         guint32 ins = *(guint32*)code;
1572         guint32 prim = (ins >> 25) & 7;
1573         guint32 ovf;
1574
1575         //g_print ("patching 0x%08x (0x%08x) to point to 0x%08x\n", code, ins, target);
1576         if (prim == 5) { /* 101b */
1577                 /* the diff starts 8 bytes from the branch opcode */
1578                 gint diff = target - code - 8;
1579                 if (diff >= 0) {
1580                         if (diff <= 33554431) {
1581                                 diff >>= 2;
1582                                 ins = (ins & 0xff000000) | diff;
1583                                 *(guint32*)code = ins;
1584                                 return;
1585                         }
1586                 } else {
1587                         /* diff between 0 and -33554432 */
1588                         if (diff >= -33554432) {
1589                                 diff >>= 2;
1590                                 ins = (ins & 0xff000000) | (diff & ~0xff000000);
1591                                 *(guint32*)code = ins;
1592                                 return;
1593                         }
1594                 }
1595                 
1596                 handle_thunk (TRUE, code, target);
1597                 return;
1598         }
1599
1600
1601         if ((ins & 0x0ffffff0) == 0x12fff10) {
1602                 /* branch and exchange: the address is constructed in a reg */
1603                 g_assert_not_reached ();
1604         } else {
1605                 guint32 ccode [3];
1606                 guint32 *tmp = ccode;
1607                 ARM_LDR_IMM (tmp, ARMREG_IP, ARMREG_PC, 0);
1608                 ARM_MOV_REG_REG (tmp, ARMREG_LR, ARMREG_PC);
1609                 ARM_MOV_REG_REG (tmp, ARMREG_PC, ARMREG_IP);
1610                 if (ins == ccode [2]) {
1611                         tmp = (guint32*)code;
1612                         tmp [-1] = (guint32)target;
1613                         return;
1614                 }
1615                 if (ins == ccode [0]) {
1616                         tmp = (guint32*)code;
1617                         tmp [2] = (guint32)target;
1618                         return;
1619                 }
1620                 g_assert_not_reached ();
1621         }
1622 //      g_print ("patched with 0x%08x\n", ins);
1623 }
1624
1625 /* 
1626  * Return the >= 0 uimm8 value if val can be represented with a byte + rotation
1627  * (with the rotation amount in *rot_amount. rot_amount is already adjusted
1628  * to be used with the emit macros.
1629  * Return -1 otherwise.
1630  */
1631 int
1632 mono_arm_is_rotated_imm8 (guint32 val, gint *rot_amount)
1633 {
1634         guint32 res, i;
1635         for (i = 0; i < 31; i+= 2) {
1636                 res = (val << (32 - i)) | (val >> i);
1637                 if (res & ~0xff)
1638                         continue;
1639                 *rot_amount = i? 32 - i: 0;
1640                 return res;
1641         }
1642         return -1;
1643 }
1644
1645 /*
1646  * Emits in code a sequence of instructions that load the value 'val'
1647  * into the dreg register. Uses at most 4 instructions.
1648  */
1649 guint8*
1650 mono_arm_emit_load_imm (guint8 *code, int dreg, guint32 val)
1651 {
1652         int imm8, rot_amount;
1653 #if 0
1654         ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
1655         /* skip the constant pool */
1656         ARM_B (code, 0);
1657         *(int*)code = val;
1658         code += 4;
1659         return code;
1660 #endif
1661         if ((imm8 = mono_arm_is_rotated_imm8 (val, &rot_amount)) >= 0) {
1662                 ARM_MOV_REG_IMM (code, dreg, imm8, rot_amount);
1663         } else if ((imm8 = mono_arm_is_rotated_imm8 (~val, &rot_amount)) >= 0) {
1664                 ARM_MVN_REG_IMM (code, dreg, imm8, rot_amount);
1665         } else {
1666                 if (val & 0xFF) {
1667                         ARM_MOV_REG_IMM8 (code, dreg, (val & 0xFF));
1668                         if (val & 0xFF00) {
1669                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF00) >> 8, 24);
1670                         }
1671                         if (val & 0xFF0000) {
1672                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
1673                         }
1674                         if (val & 0xFF000000) {
1675                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
1676                         }
1677                 } else if (val & 0xFF00) {
1678                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF00) >> 8, 24);
1679                         if (val & 0xFF0000) {
1680                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF0000) >> 16, 16);
1681                         }
1682                         if (val & 0xFF000000) {
1683                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
1684                         }
1685                 } else if (val & 0xFF0000) {
1686                         ARM_MOV_REG_IMM (code, dreg, (val & 0xFF0000) >> 16, 16);
1687                         if (val & 0xFF000000) {
1688                                 ARM_ADD_REG_IMM (code, dreg, dreg, (val & 0xFF000000) >> 24, 8);
1689                         }
1690                 }
1691                 //g_assert_not_reached ();
1692         }
1693         return code;
1694 }
1695
1696 void
1697 mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
1698 {
1699         MonoInst *ins;
1700         MonoCallInst *call;
1701         guint offset;
1702         guint8 *code = cfg->native_code + cfg->code_len;
1703         MonoInst *last_ins = NULL;
1704         guint last_offset = 0;
1705         int max_len, cpos;
1706         int imm8, rot_amount;
1707
1708         if (cfg->opt & MONO_OPT_PEEPHOLE)
1709                 peephole_pass (cfg, bb);
1710
1711         /* we don't align basic blocks of loops on arm */
1712
1713         if (cfg->verbose_level > 2)
1714                 g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset);
1715
1716         cpos = bb->max_offset;
1717
1718         if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
1719                 //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method);
1720                 //g_assert (!mono_compile_aot);
1721                 //cpos += 6;
1722                 //if (bb->cil_code)
1723                 //      cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code;
1724                 /* this is not thread save, but good enough */
1725                 /* fixme: howto handle overflows? */
1726                 //x86_inc_mem (code, &cov->data [bb->dfn].count); 
1727         }
1728
1729         ins = bb->code;
1730         while (ins) {
1731                 offset = code - cfg->native_code;
1732
1733                 max_len = ((guint8 *)arm_cpu_desc [ins->opcode])[MONO_INST_LEN];
1734
1735                 if (offset > (cfg->code_size - max_len - 16)) {
1736                         cfg->code_size *= 2;
1737                         cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
1738                         code = cfg->native_code + offset;
1739                 }
1740         //      if (ins->cil_code)
1741         //              g_print ("cil code\n");
1742                 mono_debug_record_line_number (cfg, ins, offset);
1743
1744                 switch (ins->opcode) {
1745                 case OP_MEMORY_BARRIER:
1746                         break;
1747                 case OP_TLS_GET:
1748                         g_assert_not_reached ();
1749                         break;
1750                 /*case OP_BIGMUL:
1751                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
1752                         ppc_mulhw (code, ppc_r3, ins->sreg1, ins->sreg2);
1753                         break;
1754                 case OP_BIGMUL_UN:
1755                         ppc_mullw (code, ppc_r4, ins->sreg1, ins->sreg2);
1756                         ppc_mulhwu (code, ppc_r3, ins->sreg1, ins->sreg2);
1757                         break;*/
1758                 case OP_STOREI1_MEMBASE_IMM:
1759                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFF);
1760                         g_assert (arm_is_imm12 (ins->inst_offset));
1761                         ARM_STRB_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
1762                         break;
1763                 case OP_STOREI2_MEMBASE_IMM:
1764                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm & 0xFFFF);
1765                         g_assert (arm_is_imm8 (ins->inst_offset));
1766                         ARM_STRH_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
1767                         break;
1768                 case OP_STORE_MEMBASE_IMM:
1769                 case OP_STOREI4_MEMBASE_IMM:
1770                         code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_imm);
1771                         g_assert (arm_is_imm12 (ins->inst_offset));
1772                         ARM_STR_IMM (code, ARMREG_LR, ins->inst_destbasereg, ins->inst_offset);
1773                         break;
1774                 case OP_STOREI1_MEMBASE_REG:
1775                         g_assert (arm_is_imm12 (ins->inst_offset));
1776                         ARM_STRB_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1777                         break;
1778                 case OP_STOREI2_MEMBASE_REG:
1779                         g_assert (arm_is_imm8 (ins->inst_offset));
1780                         ARM_STRH_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1781                         break;
1782                 case OP_STORE_MEMBASE_REG:
1783                 case OP_STOREI4_MEMBASE_REG:
1784                         /* this case is special, since it happens for spill code after lowering has been called */
1785                         if (arm_is_imm12 (ins->inst_offset)) {
1786                                 ARM_STR_IMM (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
1787                         } else {
1788                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
1789                                 ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ARMREG_LR);
1790                         }
1791                         break;
1792                 case OP_STOREI1_MEMINDEX:
1793                         ARM_STRB_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
1794                         break;
1795                 case OP_STOREI2_MEMINDEX:
1796                         /* note: the args are reversed in the macro */
1797                         ARM_STRH_REG_REG (code, ins->inst_destbasereg, ins->sreg1, ins->sreg2);
1798                         break;
1799                 case OP_STORE_MEMINDEX:
1800                 case OP_STOREI4_MEMINDEX:
1801                         ARM_STR_REG_REG (code, ins->sreg1, ins->inst_destbasereg, ins->sreg2);
1802                         break;
1803                 case CEE_LDIND_I:
1804                 case CEE_LDIND_I4:
1805                 case CEE_LDIND_U4:
1806                         g_assert_not_reached ();
1807                         break;
1808                 case OP_LOADU4_MEM:
1809                         g_assert_not_reached ();
1810                         break;
1811                 case OP_LOAD_MEMINDEX:
1812                 case OP_LOADI4_MEMINDEX:
1813                 case OP_LOADU4_MEMINDEX:
1814                         ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
1815                         break;
1816                 case OP_LOADI1_MEMINDEX:
1817                         /* note: the args are reversed in the macro */
1818                         ARM_LDRSB_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
1819                         break;
1820                 case OP_LOADU1_MEMINDEX:
1821                         ARM_LDRB_REG_REG (code, ins->dreg, ins->inst_basereg, ins->sreg2);
1822                         break;
1823                 case OP_LOADI2_MEMINDEX:
1824                         /* note: the args are reversed in the macro */
1825                         ARM_LDRSH_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
1826                         break;
1827                 case OP_LOADU2_MEMINDEX:
1828                         /* note: the args are reversed in the macro */
1829                         ARM_LDRH_REG_REG (code, ins->inst_basereg, ins->dreg, ins->sreg2);
1830                         break;
1831                 case OP_LOAD_MEMBASE:
1832                 case OP_LOADI4_MEMBASE:
1833                 case OP_LOADU4_MEMBASE:
1834                         /* this case is special, since it happens for spill code after lowering has been called */
1835                         if (arm_is_imm12 (ins->inst_offset)) {
1836                                 ARM_LDR_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1837                         } else {
1838                                 code = mono_arm_emit_load_imm (code, ARMREG_LR, ins->inst_offset);
1839                                 ARM_LDR_REG_REG (code, ins->dreg, ins->inst_basereg, ARMREG_LR);
1840                         }
1841                         break;
1842                 case OP_LOADI1_MEMBASE:
1843                         g_assert (arm_is_imm8 (ins->inst_offset));
1844                         ARM_LDRSB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1845                         break;
1846                 case OP_LOADU1_MEMBASE:
1847                         g_assert (arm_is_imm12 (ins->inst_offset));
1848                         ARM_LDRB_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1849                         break;
1850                 case OP_LOADU2_MEMBASE:
1851                         g_assert (arm_is_imm8 (ins->inst_offset));
1852                         ARM_LDRH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1853                         break;
1854                 case OP_LOADI2_MEMBASE:
1855                         g_assert (arm_is_imm8 (ins->inst_offset));
1856                         ARM_LDRSH_IMM (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
1857                         break;
1858                 case CEE_CONV_I1:
1859                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 24);
1860                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 24);
1861                         break;
1862                 case CEE_CONV_I2:
1863                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
1864                         ARM_SAR_IMM (code, ins->dreg, ins->dreg, 16);
1865                         break;
1866                 case CEE_CONV_U1:
1867                         ARM_AND_REG_IMM8 (code, ins->dreg, ins->sreg1, 0xff);
1868                         break;
1869                 case CEE_CONV_U2:
1870                         ARM_SHL_IMM (code, ins->dreg, ins->sreg1, 16);
1871                         ARM_SHR_IMM (code, ins->dreg, ins->dreg, 16);
1872                         break;
1873                 case OP_COMPARE:
1874                         ARM_CMP_REG_REG (code, ins->sreg1, ins->sreg2);
1875                         break;
1876                 case OP_COMPARE_IMM:
1877                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1878                         g_assert (imm8 >= 0);
1879                         ARM_CMP_REG_IMM (code, ins->sreg1, imm8, rot_amount);
1880                         break;
1881                 case CEE_BREAK:
1882                         *(int*)code = 0xe7f001f0;
1883                         *(int*)code = 0xef9f0001;
1884                         code += 4;
1885                         //ARM_DBRK (code);
1886                         break;
1887                 case OP_ADDCC:
1888                         ARM_ADDS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1889                         break;
1890                 case CEE_ADD:
1891                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1892                         break;
1893                 case OP_ADC:
1894                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1895                         break;
1896                 case OP_ADDCC_IMM:
1897                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1898                         g_assert (imm8 >= 0);
1899                         ARM_ADDS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1900                         break;
1901                 case OP_ADD_IMM:
1902                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1903                         g_assert (imm8 >= 0);
1904                         ARM_ADD_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1905                         break;
1906                 case OP_ADC_IMM:
1907                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1908                         g_assert (imm8 >= 0);
1909                         ARM_ADCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1910                         break;
1911                 case CEE_ADD_OVF:
1912                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1913                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1914                         break;
1915                 case CEE_ADD_OVF_UN:
1916                         ARM_ADD_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1917                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1918                         break;
1919                 case CEE_SUB_OVF:
1920                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1921                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1922                         break;
1923                 case CEE_SUB_OVF_UN:
1924                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1925                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
1926                         break;
1927                 case OP_ADD_OVF_CARRY:
1928                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1929                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1930                         break;
1931                 case OP_ADD_OVF_UN_CARRY:
1932                         ARM_ADCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1933                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1934                         break;
1935                 case OP_SUB_OVF_CARRY:
1936                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1937                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_FALSE, PPC_BR_EQ, "OverflowException");
1938                         break;
1939                 case OP_SUB_OVF_UN_CARRY:
1940                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1941                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_TRUE, PPC_BR_EQ, "OverflowException");
1942                         break;
1943                 case OP_SUBCC:
1944                         ARM_SUBS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1945                         break;
1946                 case OP_SUBCC_IMM:
1947                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1948                         g_assert (imm8 >= 0);
1949                         ARM_SUBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1950                         break;
1951                 case CEE_SUB:
1952                         ARM_SUB_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1953                         break;
1954                 case OP_SBB:
1955                         ARM_SBCS_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1956                         break;
1957                 case OP_SUB_IMM:
1958                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1959                         g_assert (imm8 >= 0);
1960                         ARM_SUB_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1961                         break;
1962                 case OP_SBB_IMM:
1963                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1964                         g_assert (imm8 >= 0);
1965                         ARM_SBCS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1966                         break;
1967                 case OP_ARM_RSBS_IMM:
1968                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1969                         g_assert (imm8 >= 0);
1970                         ARM_RSBS_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1971                         break;
1972                 case OP_ARM_RSC_IMM:
1973                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1974                         g_assert (imm8 >= 0);
1975                         ARM_RSC_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1976                         break;
1977                 case CEE_AND:
1978                         ARM_AND_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1979                         break;
1980                 case OP_AND_IMM:
1981                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1982                         g_assert (imm8 >= 0);
1983                         ARM_AND_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
1984                         break;
1985                 case CEE_DIV:
1986                 case CEE_DIV_UN:
1987                 case OP_DIV_IMM:
1988                 case CEE_REM:
1989                 case CEE_REM_UN:
1990                 case OP_REM_IMM:
1991                         /* crappy ARM arch doesn't have a DIV instruction */
1992                         g_assert_not_reached ();
1993                 case CEE_OR:
1994                         ARM_ORR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
1995                         break;
1996                 case OP_OR_IMM:
1997                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
1998                         g_assert (imm8 >= 0);
1999                         ARM_ORR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2000                         break;
2001                 case CEE_XOR:
2002                         ARM_EOR_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2003                         break;
2004                 case OP_XOR_IMM:
2005                         imm8 = mono_arm_is_rotated_imm8 (ins->inst_imm, &rot_amount);
2006                         g_assert (imm8 >= 0);
2007                         ARM_EOR_REG_IMM (code, ins->dreg, ins->sreg1, imm8, rot_amount);
2008                         break;
2009                 case CEE_SHL:
2010                         ARM_SHL_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2011                         break;
2012                 case OP_SHL_IMM:
2013                         if (ins->inst_imm)
2014                                 ARM_SHL_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2015                         break;
2016                 case CEE_SHR:
2017                         ARM_SAR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2018                         break;
2019                 case OP_SHR_IMM:
2020                         if (ins->inst_imm)
2021                                 ARM_SAR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2022                         break;
2023                 case OP_SHR_UN_IMM:
2024                         if (ins->inst_imm)
2025                                 ARM_SHR_IMM (code, ins->dreg, ins->sreg1, (ins->inst_imm & 0x1f));
2026                         break;
2027                 case CEE_SHR_UN:
2028                         ARM_SHR_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2029                         break;
2030                 case CEE_NOT:
2031                         ARM_MVN_REG_REG (code, ins->dreg, ins->sreg1);
2032                         break;
2033                 case CEE_NEG:
2034                         ARM_RSB_REG_IMM8 (code, ins->dreg, ins->sreg1, 0);
2035                         break;
2036                 case CEE_MUL:
2037                         if (ins->dreg == ins->sreg2)
2038                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2039                         else
2040                                 ARM_MUL_REG_REG (code, ins->dreg, ins->sreg2, ins->sreg1);
2041                         break;
2042                 case OP_MUL_IMM:
2043                         g_assert_not_reached ();
2044                         break;
2045                 case CEE_MUL_OVF:
2046                         /* FIXME: handle ovf/ sreg2 != dreg */
2047                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2048                         break;
2049                 case CEE_MUL_OVF_UN:
2050                         /* FIXME: handle ovf/ sreg2 != dreg */
2051                         ARM_MUL_REG_REG (code, ins->dreg, ins->sreg1, ins->sreg2);
2052                         break;
2053                 case OP_ICONST:
2054                 case OP_SETREGIMM:
2055                         code = mono_arm_emit_load_imm (code, ins->dreg, ins->inst_c0);
2056                         break;
2057                 case OP_AOTCONST:
2058                         g_assert_not_reached ();
2059                         mono_add_patch_info (cfg, offset, (MonoJumpInfoType)ins->inst_i1, ins->inst_p0);
2060                         break;
2061                 case CEE_CONV_I4:
2062                 case CEE_CONV_U4:
2063                 case OP_MOVE:
2064                 case OP_SETREG:
2065                         if (ins->dreg != ins->sreg1)
2066                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2067                         break;
2068                 case OP_SETLRET: {
2069                         int saved = ins->sreg2;
2070                         if (ins->sreg2 == ARM_LSW_REG) {
2071                                 ARM_MOV_REG_REG (code, ARMREG_LR, ins->sreg2);
2072                                 saved = ARMREG_LR;
2073                         }
2074                         if (ins->sreg1 != ARM_LSW_REG)
2075                                 ARM_MOV_REG_REG (code, ARM_LSW_REG, ins->sreg1);
2076                         if (saved != ARM_MSW_REG)
2077                                 ARM_MOV_REG_REG (code, ARM_MSW_REG, saved);
2078                         break;
2079                 }
2080                 case OP_SETFREG:
2081                 case OP_FMOVE:
2082                         ARM_MVFD (code, ins->dreg, ins->sreg1);
2083                         break;
2084                 case OP_FCONV_TO_R4:
2085                         ARM_MVFS (code, ins->dreg, ins->sreg1);
2086                         break;
2087                 case CEE_JMP:
2088                         /*
2089                          * Keep in sync with mono_arch_emit_epilog
2090                          */
2091                         g_assert (!cfg->method->save_lmf);
2092                         code = emit_big_add (code, ARMREG_SP, cfg->frame_reg, cfg->stack_usage);
2093                         ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP)) | ((1 << ARMREG_LR)));
2094                         mono_add_patch_info (cfg, (guint8*) code - cfg->native_code, MONO_PATCH_INFO_METHOD_JUMP, ins->inst_p0);
2095                         ARM_B (code, 0);
2096                         break;
2097                 case OP_CHECK_THIS:
2098                         /* ensure ins->sreg1 is not NULL */
2099                         ARM_LDR_IMM (code, ARMREG_LR, ins->sreg1, 0);
2100                         break;
2101                 case OP_ARGLIST: {
2102 #if ARM_PORT
2103                         if (ppc_is_imm16 (cfg->sig_cookie + cfg->stack_usage)) {
2104                                 ppc_addi (code, ppc_r11, cfg->frame_reg, cfg->sig_cookie + cfg->stack_usage);
2105                         } else {
2106                                 ppc_load (code, ppc_r11, cfg->sig_cookie + cfg->stack_usage);
2107                                 ppc_add (code, ppc_r11, cfg->frame_reg, ppc_r11);
2108                         }
2109                         ppc_stw (code, ppc_r11, 0, ins->sreg1);
2110 #endif
2111                         break;
2112                 }
2113                 case OP_FCALL:
2114                 case OP_LCALL:
2115                 case OP_VCALL:
2116                 case OP_VOIDCALL:
2117                 case CEE_CALL:
2118                         call = (MonoCallInst*)ins;
2119                         if (ins->flags & MONO_INST_HAS_METHOD)
2120                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_METHOD, call->method);
2121                         else
2122                                 mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_ABS, call->fptr);
2123                         if (cfg->method->dynamic) {
2124                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
2125                                 ARM_B (code, 0);
2126                                 *(gpointer*)code = NULL;
2127                                 code += 4;
2128                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2129                                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2130                         } else {
2131                                 ARM_BL (code, 0);
2132                         }
2133                         break;
2134                 case OP_FCALL_REG:
2135                 case OP_LCALL_REG:
2136                 case OP_VCALL_REG:
2137                 case OP_VOIDCALL_REG:
2138                 case OP_CALL_REG:
2139                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2140                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
2141                         break;
2142                 case OP_FCALL_MEMBASE:
2143                 case OP_LCALL_MEMBASE:
2144                 case OP_VCALL_MEMBASE:
2145                 case OP_VOIDCALL_MEMBASE:
2146                 case OP_CALL_MEMBASE:
2147                         g_assert (arm_is_imm12 (ins->inst_offset));
2148                         g_assert (ins->sreg1 != ARMREG_LR);
2149                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2150                         ARM_LDR_IMM (code, ARMREG_PC, ins->sreg1, ins->inst_offset);
2151                         break;
2152                 case OP_OUTARG:
2153                         g_assert_not_reached ();
2154                         break;
2155                 case OP_LOCALLOC: {
2156                         /* keep alignment */
2157                         int alloca_waste = cfg->param_area;
2158                         alloca_waste += 7;
2159                         alloca_waste &= ~7;
2160                         /* round the size to 8 bytes */
2161                         ARM_ADD_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
2162                         ARM_BIC_REG_IMM8 (code, ins->dreg, ins->sreg1, 7);
2163                         ARM_ADD_REG_IMM8 (code, ins->dreg, ins->dreg, alloca_waste);
2164                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ins->dreg);
2165                         /* memzero the area: dreg holds the size, sp is the pointer */
2166                         if (ins->flags & MONO_INST_INIT) {
2167                                 guint8 *start_loop, *branch_to_cond;
2168                                 ARM_MOV_REG_IMM8 (code, ARMREG_LR, 0);
2169                                 branch_to_cond = code;
2170                                 ARM_B (code, 0);
2171                                 start_loop = code;
2172                                 ARM_STR_REG_REG (code, ARMREG_LR, ARMREG_SP, ins->dreg);
2173                                 arm_patch (branch_to_cond, code);
2174                                 /* decrement by 4 and set flags */
2175                                 ARM_SUBS_REG_IMM8 (code, ins->dreg, ins->dreg, 4);
2176                                 ARM_B_COND (code, ARMCOND_LT, 0);
2177                                 arm_patch (code - 4, start_loop);
2178                         }
2179                         ARM_ADD_REG_IMM8 (code, ins->dreg, ARMREG_SP, alloca_waste);
2180                         break;
2181                 }
2182                 case CEE_RET:
2183                         g_assert_not_reached ();
2184                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_LR);
2185                         break;
2186                 case CEE_THROW: {
2187                         if (ins->sreg1 != ARMREG_R0)
2188                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2189                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2190                                              (gpointer)"mono_arch_throw_exception");
2191                         if (cfg->method->dynamic) {
2192                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
2193                                 ARM_B (code, 0);
2194                                 *(gpointer*)code = NULL;
2195                                 code += 4;
2196                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2197                                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2198                         } else {
2199                                 ARM_BL (code, 0);
2200                         }
2201                         break;
2202                 }
2203                 case OP_RETHROW: {
2204                         if (ins->sreg1 != ARMREG_R0)
2205                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2206                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2207                                              (gpointer)"mono_arch_rethrow_exception");
2208                         if (cfg->method->dynamic) {
2209                                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
2210                                 ARM_B (code, 0);
2211                                 *(gpointer*)code = NULL;
2212                                 code += 4;
2213                                 ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2214                                 ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2215                         } else {
2216                                 ARM_BL (code, 0);
2217                         }
2218                         break;
2219                 }
2220                 case OP_START_HANDLER:
2221                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2222                                 ARM_STR_IMM (code, ARMREG_LR, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2223                         } else {
2224                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2225                                 ARM_STR_REG_REG (code, ARMREG_LR, ins->inst_left->inst_basereg, ARMREG_IP);
2226                         }
2227                         break;
2228                 case OP_ENDFILTER:
2229                         if (ins->sreg1 != ARMREG_R0)
2230                                 ARM_MOV_REG_REG (code, ARMREG_R0, ins->sreg1);
2231                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2232                                 ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2233                         } else {
2234                                 g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
2235                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2236                                 ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
2237                         }
2238                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2239                         break;
2240                 case CEE_ENDFINALLY:
2241                         if (arm_is_imm12 (ins->inst_left->inst_offset)) {
2242                                 ARM_LDR_IMM (code, ARMREG_IP, ins->inst_left->inst_basereg, ins->inst_left->inst_offset);
2243                         } else {
2244                                 g_assert (ARMREG_IP != ins->inst_left->inst_basereg);
2245                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, ins->inst_left->inst_offset);
2246                                 ARM_LDR_REG_REG (code, ARMREG_IP, ins->inst_left->inst_basereg, ARMREG_IP);
2247                         }
2248                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2249                         break;
2250                 case OP_CALL_HANDLER: 
2251                         mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2252                         ARM_BL (code, 0);
2253                         break;
2254                 case OP_LABEL:
2255                         ins->inst_c0 = code - cfg->native_code;
2256                         break;
2257                 case CEE_BR:
2258                         if (ins->flags & MONO_INST_BRLABEL) {
2259                                 /*if (ins->inst_i0->inst_c0) {
2260                                         ARM_B (code, 0);
2261                                         //x86_jump_code (code, cfg->native_code + ins->inst_i0->inst_c0);
2262                                 } else*/ {
2263                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_LABEL, ins->inst_i0);
2264                                         ARM_B (code, 0);
2265                                 }
2266                         } else {
2267                                 /*if (ins->inst_target_bb->native_offset) {
2268                                         ARM_B (code, 0);
2269                                         //x86_jump_code (code, cfg->native_code + ins->inst_target_bb->native_offset); 
2270                                 } else*/ {
2271                                         mono_add_patch_info (cfg, offset, MONO_PATCH_INFO_BB, ins->inst_target_bb);
2272                                         ARM_B (code, 0);
2273                                 } 
2274                         }
2275                         break;
2276                 case OP_BR_REG:
2277                         ARM_MOV_REG_REG (code, ARMREG_PC, ins->sreg1);
2278                         break;
2279                 case CEE_SWITCH:
2280                         /* 
2281                          * In the normal case we have:
2282                          *      ldr pc, [pc, ins->sreg1 << 2]
2283                          *      nop
2284                          * If aot, we have:
2285                          *      ldr lr, [pc, ins->sreg1 << 2]
2286                          *      add pc, pc, lr
2287                          * After follows the data.
2288                          * FIXME: add aot support.
2289                          */
2290                         max_len += 4 * GPOINTER_TO_INT (ins->klass);
2291                         if (offset > (cfg->code_size - max_len - 16)) {
2292                                 cfg->code_size += max_len;
2293                                 cfg->code_size *= 2;
2294                                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2295                                 code = cfg->native_code + offset;
2296                         }
2297                         ARM_LDR_REG_REG_SHIFT (code, ARMREG_PC, ARMREG_PC, ins->sreg1, ARMSHIFT_LSL, 2);
2298                         ARM_NOP (code);
2299                         code += 4 * GPOINTER_TO_INT (ins->klass);
2300                         break;
2301                 case OP_CEQ:
2302                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
2303                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
2304                         break;
2305                 case OP_CLT:
2306                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2307                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LT);
2308                         break;
2309                 case OP_CLT_UN:
2310                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2311                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_LO);
2312                         break;
2313                 case OP_CGT:
2314                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2315                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_GT);
2316                         break;
2317                 case OP_CGT_UN:
2318                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2319                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_HI);
2320                         break;
2321                 case OP_COND_EXC_EQ:
2322                 case OP_COND_EXC_NE_UN:
2323                 case OP_COND_EXC_LT:
2324                 case OP_COND_EXC_LT_UN:
2325                 case OP_COND_EXC_GT:
2326                 case OP_COND_EXC_GT_UN:
2327                 case OP_COND_EXC_GE:
2328                 case OP_COND_EXC_GE_UN:
2329                 case OP_COND_EXC_LE:
2330                 case OP_COND_EXC_LE_UN:
2331                         EMIT_COND_SYSTEM_EXCEPTION (ins->opcode - OP_COND_EXC_EQ, ins->inst_p1);
2332                         break;
2333                 case OP_COND_EXC_C:
2334                 case OP_COND_EXC_OV:
2335                 case OP_COND_EXC_NC:
2336                 case OP_COND_EXC_NO:
2337                         g_assert_not_reached ();
2338                         break;
2339                 case CEE_BEQ:
2340                 case CEE_BNE_UN:
2341                 case CEE_BLT:
2342                 case CEE_BLT_UN:
2343                 case CEE_BGT:
2344                 case CEE_BGT_UN:
2345                 case CEE_BGE:
2346                 case CEE_BGE_UN:
2347                 case CEE_BLE:
2348                 case CEE_BLE_UN:
2349                         EMIT_COND_BRANCH (ins, ins->opcode - CEE_BEQ);
2350                         break;
2351
2352                 /* floating point opcodes */
2353                 case OP_R8CONST:
2354                         /* FIXME: we can optimize the imm load by dealing with part of 
2355                          * the displacement in LDFD (aligning to 512).
2356                          */
2357                         code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2358                         ARM_LDFD (code, ins->dreg, ARMREG_LR, 0);
2359                         break;
2360                 case OP_R4CONST:
2361                         code = mono_arm_emit_load_imm (code, ARMREG_LR, (guint32)ins->inst_p0);
2362                         ARM_LDFS (code, ins->dreg, ARMREG_LR, 0);
2363                         break;
2364                 case OP_STORER8_MEMBASE_REG:
2365                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2366                         ARM_STFD (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2367                         break;
2368                 case OP_LOADR8_MEMBASE:
2369                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2370                         ARM_LDFD (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2371                         break;
2372                 case OP_STORER4_MEMBASE_REG:
2373                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2374                         ARM_STFS (code, ins->sreg1, ins->inst_destbasereg, ins->inst_offset);
2375                         break;
2376                 case OP_LOADR4_MEMBASE:
2377                         g_assert (arm_is_fpimm8 (ins->inst_offset));
2378                         ARM_LDFS (code, ins->dreg, ins->inst_basereg, ins->inst_offset);
2379                         break;
2380                 case CEE_CONV_R_UN: {
2381                         int tmpreg;
2382                         tmpreg = ins->dreg == 0? 1: 0;
2383                         ARM_CMP_REG_IMM8 (code, ins->sreg1, 0);
2384                         ARM_FLTD (code, ins->dreg, ins->sreg1);
2385                         ARM_B_COND (code, ARMCOND_GE, 8);
2386                         /* save the temp register */
2387                         ARM_SUB_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
2388                         ARM_STFD (code, tmpreg, ARMREG_SP, 0);
2389                         ARM_LDFD (code, tmpreg, ARMREG_PC, 12);
2390                         ARM_FPA_ADFD (code, ins->dreg, ins->dreg, tmpreg);
2391                         ARM_LDFD (code, tmpreg, ARMREG_SP, 0);
2392                         ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_SP, 8);
2393                         /* skip the constant pool */
2394                         ARM_B (code, 8);
2395                         code += 4;
2396                         *(int*)code = 0x41f00000;
2397                         code += 4;
2398                         *(int*)code = 0;
2399                         code += 4;
2400                         /* FIXME: adjust:
2401                          * ldfltd  ftemp, [pc, #8] 0x41f00000 0x00000000
2402                          * adfltd  fdest, fdest, ftemp
2403                          */
2404                         break;
2405                 }
2406                 case CEE_CONV_R4:
2407                         ARM_FLTS (code, ins->dreg, ins->sreg1);
2408                         break;
2409                 case CEE_CONV_R8:
2410                         ARM_FLTD (code, ins->dreg, ins->sreg1);
2411                         break;
2412                 case OP_FCONV_TO_I1:
2413                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, TRUE);
2414                         break;
2415                 case OP_FCONV_TO_U1:
2416                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 1, FALSE);
2417                         break;
2418                 case OP_FCONV_TO_I2:
2419                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, TRUE);
2420                         break;
2421                 case OP_FCONV_TO_U2:
2422                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 2, FALSE);
2423                         break;
2424                 case OP_FCONV_TO_I4:
2425                 case OP_FCONV_TO_I:
2426                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, TRUE);
2427                         break;
2428                 case OP_FCONV_TO_U4:
2429                 case OP_FCONV_TO_U:
2430                         code = emit_float_to_int (cfg, code, ins->dreg, ins->sreg1, 4, FALSE);
2431                         break;
2432                 case OP_FCONV_TO_I8:
2433                 case OP_FCONV_TO_U8:
2434                         g_assert_not_reached ();
2435                         /* Implemented as helper calls */
2436                         break;
2437                 case OP_LCONV_TO_R_UN:
2438                         g_assert_not_reached ();
2439                         /* Implemented as helper calls */
2440                         break;
2441                 case OP_LCONV_TO_OVF_I: {
2442 #if ARM_PORT
2443                         guint32 *negative_branch, *msword_positive_branch, *msword_negative_branch, *ovf_ex_target;
2444                         // Check if its negative
2445                         ppc_cmpi (code, 0, 0, ins->sreg1, 0);
2446                         negative_branch = code;
2447                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_LT, 0);
2448                         // Its positive msword == 0
2449                         ppc_cmpi (code, 0, 0, ins->sreg2, 0);
2450                         msword_positive_branch = code;
2451                         ppc_bc (code, PPC_BR_TRUE, PPC_BR_EQ, 0);
2452
2453                         ovf_ex_target = code;
2454                         //EMIT_COND_SYSTEM_EXCEPTION_FLAGS (PPC_BR_ALWAYS, 0, "OverflowException");
2455                         // Negative
2456                         ppc_patch (negative_branch, code);
2457                         ppc_cmpi (code, 0, 0, ins->sreg2, -1);
2458                         msword_negative_branch = code;
2459                         ppc_bc (code, PPC_BR_FALSE, PPC_BR_EQ, 0);
2460                         ppc_patch (msword_negative_branch, ovf_ex_target);
2461                         
2462                         ppc_patch (msword_positive_branch, code);
2463                         if (ins->dreg != ins->sreg1)
2464                                 ppc_mr (code, ins->dreg, ins->sreg1);
2465 #endif
2466                         if (ins->dreg != ins->sreg1)
2467                                 ARM_MOV_REG_REG (code, ins->dreg, ins->sreg1);
2468                         break;
2469                 }
2470                 case OP_FADD:
2471                         ARM_FPA_ADFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2472                         break;
2473                 case OP_FSUB:
2474                         ARM_FPA_SUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2475                         break;          
2476                 case OP_FMUL:
2477                         ARM_FPA_MUFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2478                         break;          
2479                 case OP_FDIV:
2480                         ARM_FPA_DVFD (code, ins->dreg, ins->sreg1, ins->sreg2);
2481                         break;          
2482                 case OP_FNEG:
2483                         ARM_MNFD (code, ins->dreg, ins->sreg1);
2484                         break;          
2485                 case OP_FREM:
2486                         /* emulated */
2487                         g_assert_not_reached ();
2488                         break;
2489                 case OP_FCOMPARE:
2490                         /* each fp compare op needs to do its own */
2491                         g_assert_not_reached ();
2492                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2493                         break;
2494                 case OP_FCEQ:
2495                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2496                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 0, ARMCOND_NE);
2497                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_EQ);
2498                         break;
2499                 case OP_FCLT:
2500                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2501                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2502                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2503                         break;
2504                 case OP_FCLT_UN:
2505                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2506                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2507                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2508                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
2509                         break;
2510                 case OP_FCGT:
2511                         /* swapped */
2512                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2513                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2514                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2515                         break;
2516                 case OP_FCGT_UN:
2517                         /* swapped */
2518                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2519                         ARM_MOV_REG_IMM8 (code, ins->dreg, 0);
2520                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_MI);
2521                         ARM_MOV_REG_IMM8_COND (code, ins->dreg, 1, ARMCOND_VS);
2522                         break;
2523                 /* ARM FPA flags table:
2524                  * N        Less than               ARMCOND_MI
2525                  * Z        Equal                   ARMCOND_EQ
2526                  * C        Greater Than or Equal   ARMCOND_CS
2527                  * V        Unordered               ARMCOND_VS
2528                  */
2529                 case OP_FBEQ:
2530                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2531                         EMIT_COND_BRANCH (ins, CEE_BEQ - CEE_BEQ);
2532                         break;
2533                 case OP_FBNE_UN:
2534                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2535                         EMIT_COND_BRANCH (ins, CEE_BNE_UN - CEE_BEQ);
2536                         break;
2537                 case OP_FBLT:
2538                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2539                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
2540                         break;
2541                 case OP_FBLT_UN:
2542                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2543                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2544                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set */
2545                         break;
2546                 case OP_FBGT:
2547                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2548                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
2549                         break;
2550                 case OP_FBGT_UN:
2551                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2552                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2553                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_MI); /* N set, swapped args */
2554                         break;
2555                 case OP_FBGE:
2556                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2557                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS);
2558                         break;
2559                 case OP_FBGE_UN:
2560                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg1, ins->sreg2);
2561                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2562                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE);
2563                         break;
2564                 case OP_FBLE:
2565                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2566                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_CS); /* swapped */
2567                         break;
2568                 case OP_FBLE_UN:
2569                         ARM_FCMP (code, ARM_FPA_CMF, ins->sreg2, ins->sreg1);
2570                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_VS); /* V set */
2571                         EMIT_COND_BRANCH_FLAGS (ins, ARMCOND_GE); /* swapped */
2572                         break;
2573                 case CEE_CKFINITE: {
2574                         /*ppc_stfd (code, ins->sreg1, -8, ppc_sp);
2575                         ppc_lwz (code, ppc_r11, -8, ppc_sp);
2576                         ppc_rlwinm (code, ppc_r11, ppc_r11, 0, 1, 31);
2577                         ppc_addis (code, ppc_r11, ppc_r11, -32752);
2578                         ppc_rlwinmd (code, ppc_r11, ppc_r11, 1, 31, 31);
2579                         EMIT_COND_SYSTEM_EXCEPTION (CEE_BEQ - CEE_BEQ, "ArithmeticException");*/
2580                         g_assert_not_reached ();
2581                         break;
2582                 }
2583                 default:
2584                         g_warning ("unknown opcode %s in %s()\n", mono_inst_name (ins->opcode), __FUNCTION__);
2585                         g_assert_not_reached ();
2586                 }
2587
2588                 if ((cfg->opt & MONO_OPT_BRANCH) && ((code - cfg->native_code - offset) > max_len)) {
2589                         g_warning ("wrong maximal instruction length of instruction %s (expected %d, got %d)",
2590                                    mono_inst_name (ins->opcode), max_len, code - cfg->native_code - offset);
2591                         g_assert_not_reached ();
2592                 }
2593                
2594                 cpos += max_len;
2595
2596                 last_ins = ins;
2597                 last_offset = offset;
2598                 
2599                 ins = ins->next;
2600         }
2601
2602         cfg->code_len = code - cfg->native_code;
2603 }
2604
2605 void
2606 mono_arch_register_lowlevel_calls (void)
2607 {
2608 }
2609
2610 #define patch_lis_ori(ip,val) do {\
2611                 guint16 *__lis_ori = (guint16*)(ip);    \
2612                 __lis_ori [1] = (((guint32)(val)) >> 16) & 0xffff;      \
2613                 __lis_ori [3] = ((guint32)(val)) & 0xffff;      \
2614         } while (0)
2615
2616 void
2617 mono_arch_patch_code (MonoMethod *method, MonoDomain *domain, guint8 *code, MonoJumpInfo *ji, gboolean run_cctors)
2618 {
2619         MonoJumpInfo *patch_info;
2620
2621         for (patch_info = ji; patch_info; patch_info = patch_info->next) {
2622                 unsigned char *ip = patch_info->ip.i + code;
2623                 const unsigned char *target;
2624
2625                 if (patch_info->type == MONO_PATCH_INFO_SWITCH) {
2626                         gpointer *table = (gpointer *)patch_info->data.table->table;
2627                         gpointer *jt = (gpointer*)(ip + 8);
2628                         int i;
2629                         /* jt is the inlined jump table, 2 instructions after ip
2630                          * In the normal case we store the absolute addresses,
2631                          * otherwise the displacements.
2632                          */
2633                         for (i = 0; i < patch_info->data.table->table_size; i++) { 
2634                                 jt [i] = code + (int)patch_info->data.table->table [i];
2635                         }
2636                         continue;
2637                 }
2638                 target = mono_resolve_patch_target (method, domain, code, patch_info, run_cctors);
2639
2640                 switch (patch_info->type) {
2641                 case MONO_PATCH_INFO_IP:
2642                         g_assert_not_reached ();
2643                         patch_lis_ori (ip, ip);
2644                         continue;
2645                 case MONO_PATCH_INFO_METHOD_REL:
2646                         g_assert_not_reached ();
2647                         *((gpointer *)(ip)) = code + patch_info->data.offset;
2648                         continue;
2649                 case MONO_PATCH_INFO_METHODCONST:
2650                 case MONO_PATCH_INFO_CLASS:
2651                 case MONO_PATCH_INFO_IMAGE:
2652                 case MONO_PATCH_INFO_FIELD:
2653                 case MONO_PATCH_INFO_VTABLE:
2654                 case MONO_PATCH_INFO_IID:
2655                 case MONO_PATCH_INFO_SFLDA:
2656                 case MONO_PATCH_INFO_LDSTR:
2657                 case MONO_PATCH_INFO_TYPE_FROM_HANDLE:
2658                 case MONO_PATCH_INFO_LDTOKEN:
2659                         g_assert_not_reached ();
2660                         /* from OP_AOTCONST : lis + ori */
2661                         patch_lis_ori (ip, target);
2662                         continue;
2663                 case MONO_PATCH_INFO_R4:
2664                 case MONO_PATCH_INFO_R8:
2665                         g_assert_not_reached ();
2666                         *((gconstpointer *)(ip + 2)) = patch_info->data.target;
2667                         continue;
2668                 case MONO_PATCH_INFO_EXC_NAME:
2669                         g_assert_not_reached ();
2670                         *((gconstpointer *)(ip + 1)) = patch_info->data.name;
2671                         continue;
2672                 case MONO_PATCH_INFO_NONE:
2673                 case MONO_PATCH_INFO_BB_OVF:
2674                 case MONO_PATCH_INFO_EXC_OVF:
2675                         /* everything is dealt with at epilog output time */
2676                         continue;
2677                 default:
2678                         break;
2679                 }
2680                 arm_patch (ip, target);
2681         }
2682 }
2683
2684 /*
2685  * Stack frame layout:
2686  * 
2687  *   ------------------- fp
2688  *      MonoLMF structure or saved registers
2689  *   -------------------
2690  *      locals
2691  *   -------------------
2692  *      spilled regs
2693  *   -------------------
2694  *      optional 8 bytes for tracing
2695  *   -------------------
2696  *      param area             size is cfg->param_area
2697  *   ------------------- sp
2698  */
2699 guint8 *
2700 mono_arch_emit_prolog (MonoCompile *cfg)
2701 {
2702         MonoMethod *method = cfg->method;
2703         MonoBasicBlock *bb;
2704         MonoMethodSignature *sig;
2705         MonoInst *inst;
2706         int alloc_size, pos, max_offset, i, rot_amount;
2707         guint8 *code;
2708         CallInfo *cinfo;
2709         int tracing = 0;
2710         int lmf_offset = 0;
2711         int prev_sp_offset;
2712
2713         if (mono_jit_trace_calls != NULL && mono_trace_eval (method))
2714                 tracing = 1;
2715
2716         sig = mono_method_signature (method);
2717         cfg->code_size = 256 + sig->param_count * 20;
2718         code = cfg->native_code = g_malloc (cfg->code_size);
2719
2720         ARM_MOV_REG_REG (code, ARMREG_IP, ARMREG_SP);
2721
2722         alloc_size = cfg->stack_offset;
2723         pos = 0;
2724
2725         if (!method->save_lmf) {
2726                 ARM_PUSH (code, (cfg->used_int_regs | (1 << ARMREG_IP) | (1 << ARMREG_LR)));
2727                 prev_sp_offset = 8; /* ip and lr */
2728                 for (i = 0; i < 16; ++i) {
2729                         if (cfg->used_int_regs & (1 << i))
2730                                 prev_sp_offset += 4;
2731                 }
2732         } else {
2733                 ARM_PUSH (code, 0x5ff0);
2734                 prev_sp_offset = 4 * 10; /* all but r0-r3, sp and pc */
2735                 pos += sizeof (MonoLMF) - prev_sp_offset;
2736                 lmf_offset = pos;
2737         }
2738         alloc_size += pos;
2739         // align to MONO_ARCH_FRAME_ALIGNMENT bytes
2740         if (alloc_size & (MONO_ARCH_FRAME_ALIGNMENT - 1)) {
2741                 alloc_size += MONO_ARCH_FRAME_ALIGNMENT - 1;
2742                 alloc_size &= ~(MONO_ARCH_FRAME_ALIGNMENT - 1);
2743         }
2744
2745         /* the stack used in the pushed regs */
2746         if (prev_sp_offset & 4)
2747                 alloc_size += 4;
2748         cfg->stack_usage = alloc_size;
2749         if (alloc_size) {
2750                 if ((i = mono_arm_is_rotated_imm8 (alloc_size, &rot_amount)) >= 0) {
2751                         ARM_SUB_REG_IMM (code, ARMREG_SP, ARMREG_SP, i, rot_amount);
2752                 } else {
2753                         code = mono_arm_emit_load_imm (code, ARMREG_IP, alloc_size);
2754                         ARM_SUB_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
2755                 }
2756         }
2757         if (cfg->frame_reg != ARMREG_SP)
2758                 ARM_MOV_REG_REG (code, cfg->frame_reg, ARMREG_SP);
2759         //g_print ("prev_sp_offset: %d, alloc_size:%d\n", prev_sp_offset, alloc_size);
2760         prev_sp_offset += alloc_size;
2761
2762         /* compute max_offset in order to use short forward jumps
2763          * we could skip do it on arm because the immediate displacement
2764          * for jumps is large enough, it may be useful later for constant pools
2765          */
2766         max_offset = 0;
2767         for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
2768                 MonoInst *ins = bb->code;
2769                 bb->max_offset = max_offset;
2770
2771                 if (cfg->prof_options & MONO_PROFILE_COVERAGE)
2772                         max_offset += 6; 
2773
2774                 while (ins) {
2775                         max_offset += ((guint8 *)arm_cpu_desc [ins->opcode])[MONO_INST_LEN];
2776                         ins = ins->next;
2777                 }
2778         }
2779
2780         /* load arguments allocated to register from the stack */
2781         pos = 0;
2782
2783         cinfo = calculate_sizes (sig, sig->pinvoke);
2784
2785         if (MONO_TYPE_ISSTRUCT (sig->ret)) {
2786                 ArgInfo *ainfo = &cinfo->ret;
2787                 inst = cfg->ret;
2788                 g_assert (arm_is_imm12 (inst->inst_offset));
2789                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2790         }
2791         for (i = 0; i < sig->param_count + sig->hasthis; ++i) {
2792                 ArgInfo *ainfo = cinfo->args + i;
2793                 inst = cfg->varinfo [pos];
2794                 
2795                 if (cfg->verbose_level > 2)
2796                         g_print ("Saving argument %d (type: %d)\n", i, ainfo->regtype);
2797                 if (inst->opcode == OP_REGVAR) {
2798                         if (ainfo->regtype == RegTypeGeneral)
2799                                 ARM_MOV_REG_REG (code, inst->dreg, ainfo->reg);
2800                         else if (ainfo->regtype == RegTypeFP) {
2801                                 g_assert_not_reached ();
2802                         } else if (ainfo->regtype == RegTypeBase) {
2803                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
2804                                 ARM_LDR_IMM (code, inst->dreg, ARMREG_SP, (prev_sp_offset + ainfo->offset));
2805                         } else
2806                                 g_assert_not_reached ();
2807
2808                         if (cfg->verbose_level > 2)
2809                                 g_print ("Argument %d assigned to register %s\n", pos, mono_arch_regname (inst->dreg));
2810                 } else {
2811                         /* the argument should be put on the stack: FIXME handle size != word  */
2812                         if (ainfo->regtype == RegTypeGeneral) {
2813                                 switch (ainfo->size) {
2814                                 case 1:
2815                                         if (arm_is_imm12 (inst->inst_offset))
2816                                                 ARM_STRB_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2817                                         else {
2818                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2819                                                 ARM_STRB_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
2820                                         }
2821                                         break;
2822                                 case 2:
2823                                         if (arm_is_imm8 (inst->inst_offset)) {
2824                                                 ARM_STRH_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2825                                         } else {
2826                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2827                                                 ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
2828                                                 ARM_STRH_IMM (code, ainfo->reg, ARMREG_IP, 0);
2829                                         }
2830                                         break;
2831                                 case 8:
2832                                         g_assert (arm_is_imm12 (inst->inst_offset));
2833                                         ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2834                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
2835                                         ARM_STR_IMM (code, ainfo->reg + 1, inst->inst_basereg, inst->inst_offset + 4);
2836                                         break;
2837                                 default:
2838                                         if (arm_is_imm12 (inst->inst_offset)) {
2839                                                 ARM_STR_IMM (code, ainfo->reg, inst->inst_basereg, inst->inst_offset);
2840                                         } else {
2841                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2842                                                 ARM_STR_REG_REG (code, ainfo->reg, inst->inst_basereg, ARMREG_IP);
2843                                         }
2844                                         break;
2845                                 }
2846                         } else if (ainfo->regtype == RegTypeBase) {
2847                                 g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset));
2848                                 switch (ainfo->size) {
2849                                 case 1:
2850                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
2851                                         g_assert (arm_is_imm12 (inst->inst_offset));
2852                                         ARM_STRB_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
2853                                         break;
2854                                 case 2:
2855                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
2856                                         if (arm_is_imm8 (inst->inst_offset)) {
2857                                                 ARM_STRH_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
2858                                         } else {
2859                                                 code = mono_arm_emit_load_imm (code, ARMREG_IP, inst->inst_offset);
2860                                                 ARM_ADD_REG_REG (code, ARMREG_IP, ARMREG_IP, inst->inst_basereg);
2861                                                 ARM_STRH_IMM (code, ARMREG_LR, ARMREG_IP, 0);
2862                                         }
2863                                         break;
2864                                 case 8:
2865                                         g_assert (arm_is_imm12 (inst->inst_offset));
2866                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
2867                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
2868                                         g_assert (arm_is_imm12 (prev_sp_offset + ainfo->offset + 4));
2869                                         g_assert (arm_is_imm12 (inst->inst_offset + 4));
2870                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset + 4));
2871                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset + 4);
2872                                         break;
2873                                 default:
2874                                         g_assert (arm_is_imm12 (inst->inst_offset));
2875                                         ARM_LDR_IMM (code, ARMREG_LR, ARMREG_SP, (prev_sp_offset + ainfo->offset));
2876                                         ARM_STR_IMM (code, ARMREG_LR, inst->inst_basereg, inst->inst_offset);
2877                                         break;
2878                                 }
2879                         } else if (ainfo->regtype == RegTypeFP) {
2880                                 g_assert_not_reached ();
2881                         } else if (ainfo->regtype == RegTypeStructByVal) {
2882                                 int doffset = inst->inst_offset;
2883                                 int soffset = 0;
2884                                 int cur_reg;
2885                                 int size = 0;
2886                                 if (mono_class_from_mono_type (inst->inst_vtype))
2887                                         size = mono_class_native_size (mono_class_from_mono_type (inst->inst_vtype), NULL);
2888                                 for (cur_reg = 0; cur_reg < ainfo->size; ++cur_reg) {
2889                                         g_assert (arm_is_imm12 (doffset));
2890                                         ARM_STR_IMM (code, ainfo->reg + cur_reg, inst->inst_basereg, doffset);
2891                                         soffset += sizeof (gpointer);
2892                                         doffset += sizeof (gpointer);
2893                                 }
2894                                 if (ainfo->vtsize) {
2895                                         /* FIXME: handle overrun! with struct sizes not multiple of 4 */
2896                                         //g_print ("emit_memcpy (prev_sp_ofs: %d, ainfo->offset: %d, soffset: %d)\n", prev_sp_offset, ainfo->offset, soffset);
2897                                         code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, doffset, ARMREG_SP, prev_sp_offset + ainfo->offset);
2898                                 }
2899                         } else if (ainfo->regtype == RegTypeStructByAddr) {
2900                                 g_assert_not_reached ();
2901                                 /* FIXME: handle overrun! with struct sizes not multiple of 4 */
2902                                 code = emit_memcpy (code, ainfo->vtsize * sizeof (gpointer), inst->inst_basereg, inst->inst_offset, ainfo->reg, 0);
2903                         } else
2904                                 g_assert_not_reached ();
2905                 }
2906                 pos++;
2907         }
2908
2909         if (method->save_lmf) {
2910
2911                 mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
2912                              (gpointer)"mono_get_lmf_addr");
2913                 if (cfg->method->dynamic) {
2914                         ARM_LDR_IMM (code, ARMREG_IP, ARMREG_PC, 0);
2915                         ARM_B (code, 0);
2916                         *(gpointer*)code = NULL;
2917                         code += 4;
2918                         ARM_MOV_REG_REG (code, ARMREG_LR, ARMREG_PC);
2919                         ARM_MOV_REG_REG (code, ARMREG_PC, ARMREG_IP);
2920                 } else {
2921                         ARM_BL (code, 0);
2922                 }
2923                 /* we build the MonoLMF structure on the stack - see mini-arm.h */
2924                 /* lmf_offset is the offset from the previous stack pointer,
2925                  * alloc_size is the total stack space allocated, so the offset
2926                  * of MonoLMF from the current stack ptr is alloc_size - lmf_offset.
2927                  * The pointer to the struct is put in r1 (new_lmf).
2928                  * r2 is used as scratch
2929                  * The callee-saved registers are already in the MonoLMF structure
2930                  */
2931                 code = emit_big_add (code, ARMREG_R1, ARMREG_SP, alloc_size - lmf_offset);
2932                 /* r0 is the result from mono_get_lmf_addr () */
2933                 ARM_STR_IMM (code, ARMREG_R0, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
2934                 /* new_lmf->previous_lmf = *lmf_addr */
2935                 ARM_LDR_IMM (code, ARMREG_R2, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2936                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2937                 /* *(lmf_addr) = r1 */
2938                 ARM_STR_IMM (code, ARMREG_R1, ARMREG_R0, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
2939                 /* save method info */
2940                 code = mono_arm_emit_load_imm (code, ARMREG_R2, method);
2941                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, method));
2942                 ARM_STR_IMM (code, ARMREG_SP, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, ebp));
2943                 /* save the current IP */
2944                 ARM_MOV_REG_REG (code, ARMREG_R2, ARMREG_PC);
2945                 ARM_STR_IMM (code, ARMREG_R2, ARMREG_R1, G_STRUCT_OFFSET (MonoLMF, eip));
2946         }
2947
2948         if (tracing)
2949                 code = mono_arch_instrument_prolog (cfg, mono_trace_enter_method, code, TRUE);
2950
2951         cfg->code_len = code - cfg->native_code;
2952         g_assert (cfg->code_len < cfg->code_size);
2953         g_free (cinfo);
2954
2955         return code;
2956 }
2957
2958 void
2959 mono_arch_emit_epilog (MonoCompile *cfg)
2960 {
2961         MonoJumpInfo *patch_info;
2962         MonoMethod *method = cfg->method;
2963         int pos, i, rot_amount;
2964         int max_epilog_size = 16 + 20*4;
2965         guint8 *code;
2966
2967         if (cfg->method->save_lmf)
2968                 max_epilog_size += 128;
2969         
2970         if (mono_jit_trace_calls != NULL)
2971                 max_epilog_size += 50;
2972
2973         if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE)
2974                 max_epilog_size += 50;
2975
2976         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
2977                 cfg->code_size *= 2;
2978                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
2979                 mono_jit_stats.code_reallocs++;
2980         }
2981
2982         /*
2983          * Keep in sync with CEE_JMP
2984          */
2985         code = cfg->native_code + cfg->code_len;
2986
2987         if (mono_jit_trace_calls != NULL && mono_trace_eval (method)) {
2988                 code = mono_arch_instrument_epilog (cfg, mono_trace_leave_method, code, TRUE);
2989         }
2990         pos = 0;
2991
2992         if (method->save_lmf) {
2993                 int lmf_offset;
2994                 /* all but r0-r3, sp and pc */
2995                 pos += sizeof (MonoLMF) - (4 * 10);
2996                 lmf_offset = pos;
2997                 /* r2 contains the pointer to the current LMF */
2998                 code = emit_big_add (code, ARMREG_R2, cfg->frame_reg, cfg->stack_usage - lmf_offset);
2999                 /* ip = previous_lmf */
3000                 ARM_LDR_IMM (code, ARMREG_IP, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3001                 /* lr = lmf_addr */
3002                 ARM_LDR_IMM (code, ARMREG_LR, ARMREG_R2, G_STRUCT_OFFSET (MonoLMF, lmf_addr));
3003                 /* *(lmf_addr) = previous_lmf */
3004                 ARM_STR_IMM (code, ARMREG_IP, ARMREG_LR, G_STRUCT_OFFSET (MonoLMF, previous_lmf));
3005                 /* FIXME: speedup: there is no actual need to restore the registers if
3006                  * we didn't actually change them (idea from Zoltan).
3007                  */
3008                 /* restore iregs */
3009                 /* point sp at the registers to restore: 10 is 14 -4, because we skip r0-r3 */
3010                 ARM_ADD_REG_IMM8 (code, ARMREG_SP, ARMREG_R2, (sizeof (MonoLMF) - 10 * sizeof (gulong)));
3011                 ARM_POP_NWB (code, 0xaff0); /* restore ip to sp and lr to pc */
3012         } else {
3013                 if ((i = mono_arm_is_rotated_imm8 (cfg->stack_usage, &rot_amount)) >= 0) {
3014                         ARM_ADD_REG_IMM (code, ARMREG_SP, cfg->frame_reg, i, rot_amount);
3015                 } else {
3016                         code = mono_arm_emit_load_imm (code, ARMREG_IP, cfg->stack_usage);
3017                         ARM_ADD_REG_REG (code, ARMREG_SP, ARMREG_SP, ARMREG_IP);
3018                 }
3019                 ARM_POP_NWB (code, cfg->used_int_regs | ((1 << ARMREG_SP) | (1 << ARMREG_PC)));
3020         }
3021
3022         cfg->code_len = code - cfg->native_code;
3023
3024         g_assert (cfg->code_len < cfg->code_size);
3025
3026 }
3027
3028 /* remove once throw_exception_by_name is eliminated */
3029 static int
3030 exception_id_by_name (const char *name)
3031 {
3032         if (strcmp (name, "IndexOutOfRangeException") == 0)
3033                 return MONO_EXC_INDEX_OUT_OF_RANGE;
3034         if (strcmp (name, "OverflowException") == 0)
3035                 return MONO_EXC_OVERFLOW;
3036         if (strcmp (name, "ArithmeticException") == 0)
3037                 return MONO_EXC_ARITHMETIC;
3038         if (strcmp (name, "DivideByZeroException") == 0)
3039                 return MONO_EXC_DIVIDE_BY_ZERO;
3040         if (strcmp (name, "InvalidCastException") == 0)
3041                 return MONO_EXC_INVALID_CAST;
3042         if (strcmp (name, "NullReferenceException") == 0)
3043                 return MONO_EXC_NULL_REF;
3044         if (strcmp (name, "ArrayTypeMismatchException") == 0)
3045                 return MONO_EXC_ARRAY_TYPE_MISMATCH;
3046         g_error ("Unknown intrinsic exception %s\n", name);
3047 }
3048
3049 void
3050 mono_arch_emit_exceptions (MonoCompile *cfg)
3051 {
3052         MonoJumpInfo *patch_info;
3053         int nthrows, i;
3054         guint8 *code;
3055         const guint8* exc_throw_pos [MONO_EXC_INTRINS_NUM] = {NULL};
3056         guint8 exc_throw_found [MONO_EXC_INTRINS_NUM] = {0};
3057         guint32 code_size;
3058         int exc_count = 0;
3059         int max_epilog_size = 50;
3060
3061         /* count the number of exception infos */
3062      
3063         /* 
3064          * make sure we have enough space for exceptions
3065          * 12 is the simulated call to throw_exception_by_name
3066          */
3067         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3068                 if (patch_info->type == MONO_PATCH_INFO_EXC) {
3069                         i = exception_id_by_name (patch_info->data.target);
3070                         if (!exc_throw_found [i]) {
3071                                 max_epilog_size += 12;
3072                                 exc_throw_found [i] = TRUE;
3073                         }
3074                 }
3075         }
3076
3077         while (cfg->code_len + max_epilog_size > (cfg->code_size - 16)) {
3078                 cfg->code_size *= 2;
3079                 cfg->native_code = g_realloc (cfg->native_code, cfg->code_size);
3080                 mono_jit_stats.code_reallocs++;
3081         }
3082
3083         code = cfg->native_code + cfg->code_len;
3084
3085         /* add code to raise exceptions */
3086         for (patch_info = cfg->patch_info; patch_info; patch_info = patch_info->next) {
3087                 switch (patch_info->type) {
3088                 case MONO_PATCH_INFO_EXC: {
3089                         unsigned char *ip = patch_info->ip.i + cfg->native_code;
3090                         const char *ex_name = patch_info->data.target;
3091                         i = exception_id_by_name (patch_info->data.target);
3092                         if (exc_throw_pos [i]) {
3093                                 arm_patch (ip, exc_throw_pos [i]);
3094                                 patch_info->type = MONO_PATCH_INFO_NONE;
3095                                 break;
3096                         } else {
3097                                 exc_throw_pos [i] = code;
3098                         }
3099                         arm_patch (ip, code);
3100                         //*(int*)code = 0xef9f0001;
3101                         code += 4;
3102                         /*mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_EXC_NAME, patch_info->data.target);*/
3103                         ARM_LDR_IMM (code, ARMREG_R0, ARMREG_PC, 0);
3104                         /* we got here from a conditional call, so the calling ip is set in lr already */
3105                         patch_info->type = MONO_PATCH_INFO_INTERNAL_METHOD;
3106                         patch_info->data.name = "mono_arch_throw_exception_by_name";
3107                         patch_info->ip.i = code - cfg->native_code;
3108                         ARM_B (code, 0);
3109                         *(gpointer*)code = ex_name;
3110                         code += 4;
3111                         break;
3112                 }
3113                 default:
3114                         /* do nothing */
3115                         break;
3116                 }
3117         }
3118
3119         cfg->code_len = code - cfg->native_code;
3120
3121         g_assert (cfg->code_len < cfg->code_size);
3122
3123 }
3124
3125 void
3126 mono_arch_setup_jit_tls_data (MonoJitTlsData *tls)
3127 {
3128 }
3129
3130 void
3131 mono_arch_free_jit_tls_data (MonoJitTlsData *tls)
3132 {
3133 }
3134
3135 void
3136 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
3137 {
3138         
3139         int this_dreg = ARMREG_R0;
3140         
3141         if (vt_reg != -1)
3142                 this_dreg = ARMREG_R1;
3143
3144         /* add the this argument */
3145         if (this_reg != -1) {
3146                 MonoInst *this;
3147                 MONO_INST_NEW (cfg, this, OP_SETREG);
3148                 this->type = this_type;
3149                 this->sreg1 = this_reg;
3150                 this->dreg = mono_regstate_next_int (cfg->rs);
3151                 mono_bblock_add_inst (cfg->cbb, this);
3152                 mono_call_inst_add_outarg_reg (cfg, inst, this->dreg, this_dreg, FALSE);
3153         }
3154
3155         if (vt_reg != -1) {
3156                 MonoInst *vtarg;
3157                 MONO_INST_NEW (cfg, vtarg, OP_SETREG);
3158                 vtarg->type = STACK_MP;
3159                 vtarg->sreg1 = vt_reg;
3160                 vtarg->dreg = mono_regstate_next_int (cfg->rs);
3161                 mono_bblock_add_inst (cfg->cbb, vtarg);
3162                 mono_call_inst_add_outarg_reg (cfg, inst, vtarg->dreg, ARMREG_R0, FALSE);
3163         }
3164 }
3165
3166 MonoInst*
3167 mono_arch_get_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
3168 {
3169         MonoInst *ins = NULL;
3170         if (cmethod->klass == mono_defaults.thread_class &&
3171                         strcmp (cmethod->name, "MemoryBarrier") == 0) {
3172                 MONO_INST_NEW (cfg, ins, OP_MEMORY_BARRIER);
3173         }
3174         return ins;
3175 }
3176
3177 gboolean
3178 mono_arch_print_tree (MonoInst *tree, int arity)
3179 {
3180         return 0;
3181 }
3182
3183 MonoInst* mono_arch_get_domain_intrinsic (MonoCompile* cfg)
3184 {
3185         return NULL;
3186 }
3187
3188 MonoInst* 
3189 mono_arch_get_thread_intrinsic (MonoCompile* cfg)
3190 {
3191         return NULL;
3192 }
3193
3194 void
3195 mono_arch_flush_register_windows (void)
3196 {
3197 }
3198
3199 void
3200 mono_arch_fixup_jinfo (MonoCompile *cfg)
3201 {
3202         /* max encoded stack usage is 64KB * 4 */
3203         g_assert ((cfg->stack_usage & ~(0xffff << 2)) == 0);
3204         cfg->jit_info->used_regs |= cfg->stack_usage << 14;
3205 }
3206