[eglib] Prefer <langinfo.h> to <localcharset.h>
[mono.git] / mono / arch / arm / tramp.c
1 /*
2  * Create trampolines to invoke arbitrary functions.
3  * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com>
4  *
5  * Contributions by Malte Hildingson
6  */
7
8 #include "arm-codegen.h"
9 #include "arm-dis.h"
10
11 #if defined(_WIN32_WCE) || defined (UNDER_CE)
12 #       include <windows.h>
13 #else
14 #include <unistd.h>
15 #include <sys/mman.h>
16 #endif
17
18 #if !defined(PLATFORM_MACOSX)
19 #include <errno.h>
20
21 #include "mono/metadata/class.h"
22 #include "mono/metadata/tabledefs.h"
23 #include "mono/interpreter/interp.h"
24 #include "mono/metadata/appdomain.h"
25
26
27 #if 0
28 #       define ARM_DUMP_DISASM 1
29 #endif
30
31 /* prototypes for private functions (to avoid compiler warnings) */
32 void flush_icache (void);
33 void* alloc_code_buff (int num_instr);
34
35
36
37 /*
38  * The resulting function takes the form:
39  * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments);
40  * NOTE: all args passed in ARM registers (A1-A4),
41  *       then copied to R4-R7 (see definitions below).
42  */
43
44 #define REG_FUNC_ADDR ARMREG_R4
45 #define REG_RETVAL    ARMREG_R5
46 #define REG_THIS      ARMREG_R6
47 #define REG_ARGP      ARMREG_R7
48
49
50 #define ARG_SIZE sizeof(stackval)
51
52
53
54
55 void flush_icache ()
56 {
57 #if defined(_WIN32)
58         FlushInstructionCache(GetCurrentProcess(), NULL, 0);
59 #else
60 # if 0
61         asm ("mov r0, r0");
62         asm ("mov r0, #0");
63         asm ("mcr p15, 0, r0, c7, c7, 0");
64 # else
65         /* TODO: use (movnv  pc, rx) method */
66 # endif
67 #endif
68 }
69
70
71 void* alloc_code_buff (int num_instr)
72 {
73         void* code_buff;
74         int code_size = num_instr * sizeof(arminstr_t);
75
76 #if defined(_WIN32) || defined(UNDER_CE)
77         int old_prot = 0;
78
79         code_buff = malloc(code_size);
80         VirtualProtect(code_buff, code_size, PAGE_EXECUTE_READWRITE, &old_prot);
81 #else
82         int page_size = sysconf(_SC_PAGESIZE);
83         int new_code_size;
84
85         new_code_size = code_size + page_size - 1;
86         code_buff = malloc(new_code_size);
87         code_buff = (void *) (((int) code_buff + page_size - 1) & ~(page_size - 1));
88
89         if (mprotect(code_buff, code_size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) {
90                 g_critical (G_GNUC_PRETTY_FUNCTION
91                                 ": mprotect error: %s", g_strerror (errno));
92         }
93 #endif
94
95         return code_buff;
96 }
97
98
99 /*
100  * Refer to ARM Procedure Call Standard (APCS) for more info.
101  */
102 MonoPIFunc mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor)
103 {
104         MonoType* param;
105         MonoPIFunc code_buff;
106         arminstr_t* p;
107         guint32 code_size, stack_size;
108         guint32 simple_type;
109         int i, hasthis, aregs, regc, stack_offs;
110         int this_loaded;
111         guchar reg_alloc [ARM_NUM_ARG_REGS];
112
113         /* pessimistic estimation for prologue/epilogue size */
114         code_size = 16 + 16;
115         /* push/pop work regs */
116         code_size += 2; 
117         /* call */
118         code_size += 2;
119         /* handle retval */
120         code_size += 2;
121
122         stack_size = 0;
123         hasthis = sig->hasthis ? 1 : 0;
124
125         aregs = ARM_NUM_ARG_REGS - hasthis;
126
127         for (i = 0, regc = aregs; i < sig->param_count; ++i) {
128                 param = sig->params [i];
129
130                 /* keep track of argument sizes */
131                 if (i < ARM_NUM_ARG_REGS) reg_alloc [i] = 0;
132
133                 if (param->byref) {
134                         if (regc > 0) {
135                                 code_size += 1;
136                                 reg_alloc [i] = regc;
137                                 --regc;
138                         } else {
139                                 code_size += 2;
140                                 stack_size += sizeof(gpointer);
141                         }
142                 } else {
143                         simple_type = param->type;
144 enum_calc_size:
145                         switch (simple_type) {
146                         case MONO_TYPE_BOOLEAN:
147                         case MONO_TYPE_CHAR:
148                         case MONO_TYPE_I1:
149                         case MONO_TYPE_U1:
150                         case MONO_TYPE_I2:
151                         case MONO_TYPE_U2:
152                         case MONO_TYPE_I4:
153                         case MONO_TYPE_U4:
154                         case MONO_TYPE_I:
155                         case MONO_TYPE_U:
156                         case MONO_TYPE_PTR:
157                         case MONO_TYPE_R4:
158                         case MONO_TYPE_SZARRAY:
159                         case MONO_TYPE_CLASS:
160                         case MONO_TYPE_OBJECT:
161                         case MONO_TYPE_STRING:
162                                 if (regc > 0) {
163                                         /* register arg */
164                                         code_size += 1;
165                                         reg_alloc [i] = regc;
166                                         --regc;
167                                 } else {
168                                         /* stack arg */
169                                         code_size += 2;
170                                         stack_size += 4;
171                                 }
172                                 break;
173                         case MONO_TYPE_I8:
174                         case MONO_TYPE_U8:
175                         case MONO_TYPE_R8:
176                                 /* keep track of argument sizes */
177                                 if (regc > 1) {
178                                         /* fits into registers, two LDRs */
179                                         code_size += 2;
180                                         reg_alloc [i] = regc;
181                                         regc -= 2;
182                                 } else if (regc > 0) {
183                                         /* first half fits into register, one LDR */
184                                         code_size += 1;
185                                         reg_alloc [i] = regc;
186                                         --regc;
187                                         /* the rest on the stack, LDR/STR */
188                                         code_size += 2;
189                                         stack_size += 4;
190                                 } else {
191                                         /* stack arg, 4 instrs - 2x(LDR/STR) */
192                                         code_size += 4;
193                                         stack_size += 2 * 4;
194                                 }
195                                 break;
196                         case MONO_TYPE_VALUETYPE:
197                                 if (param->data.klass->enumtype) {
198                                         simple_type = param->data.klass->enum_basetype->type;
199                                         goto enum_calc_size;
200                                 }
201
202                                 if (mono_class_value_size(param->data.klass, NULL) != 4) {
203                                         g_error("can only marshal enums, not generic structures (size: %d)", mono_class_value_size(param->data.klass, NULL));
204                                 }
205                                 if (regc > 0) {
206                                         /* register arg */
207                                         code_size += 1;
208                                         reg_alloc [i] = regc;
209                                         --regc;
210                                 } else {
211                                         /* stack arg */
212                                         code_size += 2;
213                                         stack_size += 4;
214                                 }
215                                 break;
216                         default :
217                                 break;
218                         }
219                 }
220         }
221
222         code_buff = (MonoPIFunc)alloc_code_buff(code_size);
223         p = (arminstr_t*)code_buff;
224
225         /* prologue */
226         p = arm_emit_lean_prologue(p, stack_size,
227                 /* save workset (r4-r7) */
228                 (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6) | (1 << ARMREG_R7));
229
230
231         /* copy args into workset */
232         /* callme - always present */
233         ARM_MOV_REG_REG(p, ARMREG_R4, ARMREG_A1);
234         /* retval */
235         if (sig->ret->byref || string_ctor || (sig->ret->type != MONO_TYPE_VOID)) {
236                 ARM_MOV_REG_REG(p, ARMREG_R5, ARMREG_A2);
237         }
238         /* this_obj */
239         if (sig->hasthis) {
240                 this_loaded = 0;
241                 if (stack_size == 0) {
242                         ARM_MOV_REG_REG(p, ARMREG_A1, ARMREG_A3);
243                         this_loaded = 1;
244                 } else {
245                         ARM_MOV_REG_REG(p, ARMREG_R6, ARMREG_A3);
246                 }
247         }
248         /* args */
249         if (sig->param_count != 0) {
250                 ARM_MOV_REG_REG(p, ARMREG_R7, ARMREG_A4);
251         }
252
253         stack_offs = stack_size;
254
255         /* handle arguments */
256         /* in reverse order so we could use r0 (arg1) for memory transfers */
257         for (i = sig->param_count; --i >= 0;) {
258                 param = sig->params [i];
259                 if (param->byref) {
260                         if (i < aregs && reg_alloc[i] > 0) {
261                                 ARM_LDR_IMM(p, ARMREG_A1 + i, REG_ARGP, i*ARG_SIZE);
262                         } else {
263                                 stack_offs -= sizeof(armword_t);
264                                 ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
265                                 ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
266                         }
267                 } else {
268                         simple_type = param->type;
269 enum_marshal:
270                         switch (simple_type) {
271                         case MONO_TYPE_BOOLEAN:
272                         case MONO_TYPE_CHAR:
273                         case MONO_TYPE_I1:
274                         case MONO_TYPE_U1:
275                         case MONO_TYPE_I2:
276                         case MONO_TYPE_U2:
277                         case MONO_TYPE_I4:
278                         case MONO_TYPE_U4:
279                         case MONO_TYPE_I:
280                         case MONO_TYPE_U:
281                         case MONO_TYPE_PTR:
282                         case MONO_TYPE_R4:
283                         case MONO_TYPE_SZARRAY:
284                         case MONO_TYPE_CLASS:
285                         case MONO_TYPE_OBJECT:
286                         case MONO_TYPE_STRING:
287                                 if (i < aregs && reg_alloc [i] > 0) {
288                                         /* pass in register */
289                                         ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
290                                 } else {
291                                         stack_offs -= sizeof(armword_t);
292                                         ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
293                                         ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
294                                 }
295                                 break;
296                         case MONO_TYPE_I8:
297                         case MONO_TYPE_U8:
298                         case MONO_TYPE_R8:
299                                 if (i < aregs && reg_alloc [i] > 0) {
300                                         if (reg_alloc [i] > 1) {
301                                                 /* pass in registers */
302                                                 ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
303                                                 ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]) + 1, REG_ARGP, i*ARG_SIZE + 4);
304                                         } else {
305                                                 stack_offs -= sizeof(armword_t);
306                                                 ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE + 4);
307                                                 ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
308                                                 ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE);
309                                         }
310                                 } else {
311                                         /* two words transferred on the stack */
312                                         stack_offs -= 2*sizeof(armword_t);
313                                         ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE);
314                                         ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
315                                         ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE + 4);
316                                         ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs + 4);
317                                 }
318                                 break;
319                         case MONO_TYPE_VALUETYPE:
320                                 if (param->data.klass->enumtype) {
321                                         /* it's an enum value, proceed based on its base type */
322                                         simple_type = param->data.klass->enum_basetype->type;
323                                         goto enum_marshal;
324                                 } else {
325                                         if (i < aregs && reg_alloc[i] > 0) {
326                                                 int vtreg = ARMREG_A1 + hasthis +
327                                                                 hasthis + (aregs - reg_alloc[i]);
328                                                 ARM_LDR_IMM(p, vtreg, REG_ARGP, i * ARG_SIZE);
329                                                 ARM_LDR_IMM(p, vtreg, vtreg, 0);
330                                         } else {
331                                                 stack_offs -= sizeof(armword_t);
332                                                 ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i * ARG_SIZE);
333                                                 ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R0, 0);
334                                                 ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs);
335                                         }
336                                 }
337                                 break;
338
339                         default:
340                                 break;
341                         }
342                 }
343         }
344
345         if (sig->hasthis && !this_loaded) {
346                 /* [this] always passed in A1, regardless of sig->call_convention */
347                 ARM_MOV_REG_REG(p, ARMREG_A1, REG_THIS);
348         }
349
350         /* call [func] */
351         ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
352         ARM_MOV_REG_REG(p, ARMREG_PC, REG_FUNC_ADDR);
353
354         /* handle retval */
355         if (sig->ret->byref || string_ctor) {
356                 ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
357         } else {
358                 simple_type = sig->ret->type;
359 enum_retvalue:
360                 switch (simple_type) {
361                 case MONO_TYPE_BOOLEAN:
362                 case MONO_TYPE_I1:
363                 case MONO_TYPE_U1:
364                         ARM_STRB_IMM(p, ARMREG_R0, REG_RETVAL, 0);
365                         break;
366                 case MONO_TYPE_CHAR:
367                 case MONO_TYPE_I2:
368                 case MONO_TYPE_U2:
369                         ARM_STRH_IMM(p, ARMREG_R0, REG_RETVAL, 0);
370                         break;
371                 /*
372                  * A 32-bit integer and integer-equivalent return value
373                  * is returned in R0.
374                  * Single-precision floating-point values are returned in R0.
375                  */
376                 case MONO_TYPE_I:
377                 case MONO_TYPE_U:
378                 case MONO_TYPE_I4:
379                 case MONO_TYPE_U4:
380                 case MONO_TYPE_R4:
381                 case MONO_TYPE_OBJECT:
382                 case MONO_TYPE_CLASS:
383                 case MONO_TYPE_ARRAY:
384                 case MONO_TYPE_SZARRAY:
385                 case MONO_TYPE_STRING:
386                         ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
387                         break;
388                 /*
389                  * A 64-bit integer is returned in R0 and R1.
390                  * Double-precision floating-point values are returned in R0 and R1.
391                  */
392                 case MONO_TYPE_I8:
393                 case MONO_TYPE_U8:
394                 case MONO_TYPE_R8:
395                         ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0);
396                         ARM_STR_IMM(p, ARMREG_R1, REG_RETVAL, 4);
397                         break;
398                 case MONO_TYPE_VALUETYPE:
399                         if (sig->ret->data.klass->enumtype) {
400                                 simple_type = sig->ret->data.klass->enum_basetype->type;
401                                 goto enum_retvalue;
402                         }
403                         break;
404                 case MONO_TYPE_VOID:
405                         break;
406                 default:
407                         break;
408                 }
409         }
410         
411         p = arm_emit_std_epilogue(p, stack_size,
412                 /* restore R4-R7 */
413                 (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6) | (1 << ARMREG_R7));
414
415         flush_icache();
416
417 #ifdef ARM_DUMP_DISASM
418         _armdis_decode((arminstr_t*)code_buff, ((guint8*)p) - ((guint8*)code_buff));
419 #endif
420
421         return code_buff;
422 }
423
424
425
426 #define MINV_OFFS(member) G_STRUCT_OFFSET(MonoInvocation, member)
427
428
429
430 /*
431  * Returns a pointer to a native function that can be used to
432  * call the specified method.
433  * The function created will receive the arguments according
434  * to the call convention specified in the method.
435  * This function works by creating a MonoInvocation structure,
436  * filling the fields in and calling ves_exec_method on it.
437  * Still need to figure out how to handle the exception stuff
438  * across the managed/unmanaged boundary.
439  */
440 void* mono_arch_create_method_pointer (MonoMethod* method)
441 {
442         MonoMethodSignature* sig;
443         guchar* p, * p_method, * p_stackval_from_data, * p_exec;
444         void* code_buff;
445         int i, stack_size, arg_pos, arg_add, stackval_pos, offs;
446         int areg, reg_args, shift, pos;
447         MonoJitInfo *ji;
448
449         code_buff = alloc_code_buff(128);
450         p = (guchar*)code_buff;
451
452         sig = method->signature;
453
454         ARM_B(p, 3);
455
456         /* embed magic number followed by method pointer */
457         *p++ = 'M';
458         *p++ = 'o';
459         *p++ = 'n';
460         *p++ = 'o';
461         /* method ptr */
462         *(void**)p = method;
463         p_method = p;
464         p += 4;
465
466         /* call table */
467         *(void**)p = stackval_from_data;
468         p_stackval_from_data = p;
469         p += 4;
470         *(void**)p = ves_exec_method;
471         p_exec = p;
472         p += 4;
473
474         stack_size = sizeof(MonoInvocation) + ARG_SIZE*(sig->param_count + 1) + ARM_NUM_ARG_REGS*2*sizeof(armword_t);
475
476         /* prologue */
477         p = (guchar*)arm_emit_lean_prologue((arminstr_t*)p, stack_size,
478             (1 << ARMREG_R4) |
479             (1 << ARMREG_R5) |
480             (1 << ARMREG_R6) |
481             (1 << ARMREG_R7));
482
483         /* R7 - ptr to stack args */
484         ARM_MOV_REG_REG(p, ARMREG_R7, ARMREG_IP);
485
486         /*
487          * Initialize MonoInvocation fields, first the ones known now.
488          */
489         ARM_MOV_REG_IMM8(p, ARMREG_R4, 0);
490         ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(ex));
491         ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(ex_handler));
492         ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(parent));
493
494         /* Set the method pointer. */
495         ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, -(int)(p - p_method + sizeof(arminstr_t)*2));
496         ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(method));
497
498         if (sig->hasthis) {
499                 /* [this] in A1 */
500                 ARM_STR_IMM(p, ARMREG_A1, ARMREG_SP, MINV_OFFS(obj));
501         } else {
502                 /* else set minv.obj to NULL */
503                 ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(obj));
504         }
505
506         /* copy args from registers to stack */
507         areg = ARMREG_A1 + sig->hasthis;
508         arg_pos = -(int)(ARM_NUM_ARG_REGS - sig->hasthis) * 2 * sizeof(armword_t);
509         arg_add = 0;
510         for (i = 0; i < sig->param_count; ++i) {
511                 if (areg >= ARM_NUM_ARG_REGS) break;
512                 ARM_STR_IMM(p, areg, ARMREG_R7, arg_pos);
513                 ++areg;
514                 if (!sig->params[i]->byref) {
515                         switch (sig->params[i]->type) {
516                         case MONO_TYPE_I8:
517                         case MONO_TYPE_U8:
518                         case MONO_TYPE_R8:
519                                 if (areg >= ARM_NUM_ARG_REGS) {
520                                         /* load second half of 64-bit arg */
521                                         ARM_LDR_IMM(p, ARMREG_R4, ARMREG_R7, 0);
522                                         ARM_STR_IMM(p, ARMREG_R4, ARMREG_R7, arg_pos + sizeof(armword_t));
523                                         arg_add = sizeof(armword_t);
524                                 } else {
525                                         /* second half is already the register */
526                                         ARM_STR_IMM(p, areg, ARMREG_R7, arg_pos + sizeof(armword_t));
527                                         ++areg;
528                                 }
529                                 break;
530                         case MONO_TYPE_VALUETYPE:
531                                 /* assert */
532                         default:
533                                 break;
534                         }
535                 }
536                 arg_pos += 2 * sizeof(armword_t);
537         }
538         /* number of args passed in registers */
539         reg_args = i;
540
541
542
543         /*
544          * Calc and save stack args ptr,
545          * args follow MonoInvocation struct on the stack.
546          */
547         ARM_ADD_REG_IMM8(p, ARMREG_R1, ARMREG_SP, sizeof(MonoInvocation));
548         ARM_STR_IMM(p, ARMREG_R1, ARMREG_SP, MINV_OFFS(stack_args));
549
550         /* convert method args to stackvals */
551         arg_pos = -(int)(ARM_NUM_ARG_REGS - sig->hasthis) * 2 * sizeof(armword_t);
552         stackval_pos = sizeof(MonoInvocation);
553         for (i = 0; i < sig->param_count; ++i) {
554                 if (i < reg_args) {
555                         ARM_SUB_REG_IMM8(p, ARMREG_A3, ARMREG_R7, -arg_pos);
556                         arg_pos += 2 * sizeof(armword_t);
557                 } else {
558                         if (arg_pos < 0) arg_pos = 0;
559                         pos = arg_pos + arg_add;
560                         if (pos <= 0xFF) {
561                                 ARM_ADD_REG_IMM8(p, ARMREG_A3, ARMREG_R7, pos);
562                         } else {
563                                 if (is_arm_const((armword_t)pos)) {
564                                         shift = calc_arm_mov_const_shift((armword_t)pos);
565                                         ARM_ADD_REG_IMM(p, ARMREG_A3, ARMREG_R7, pos >> ((32 - shift) & 31), shift >> 1);
566                                 } else {
567                                         p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R6, (armword_t)pos);
568                                         ARM_ADD_REG_REG(p, ARMREG_A2, ARMREG_R7, ARMREG_R6);
569                                 }
570                         }
571                         arg_pos += sizeof(armword_t);
572                         if (!sig->params[i]->byref) {
573                                 switch (sig->params[i]->type) {
574                                 case MONO_TYPE_I8:
575                                 case MONO_TYPE_U8:
576                                 case MONO_TYPE_R8:
577                                         arg_pos += sizeof(armword_t);
578                                         break;
579                                 case MONO_TYPE_VALUETYPE:
580                                         /* assert */
581                                 default:
582                                         break;
583                                 }
584                         }
585                 }
586
587                 /* A2 = result */
588                 if (stackval_pos <= 0xFF) {
589                         ARM_ADD_REG_IMM8(p, ARMREG_A2, ARMREG_SP, stackval_pos);
590                 } else {
591                         if (is_arm_const((armword_t)stackval_pos)) {
592                                 shift = calc_arm_mov_const_shift((armword_t)stackval_pos);
593                                 ARM_ADD_REG_IMM(p, ARMREG_A2, ARMREG_SP, stackval_pos >> ((32 - shift) & 31), shift >> 1);
594                         } else {
595                                 p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R6, (armword_t)stackval_pos);
596                                 ARM_ADD_REG_REG(p, ARMREG_A2, ARMREG_SP, ARMREG_R6);
597                         }
598                 }
599
600                 /* A1 = type */
601                 p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_A1, (armword_t)sig->params [i]);
602
603                 stackval_pos += ARG_SIZE;
604
605                 offs = -(p + 2*sizeof(arminstr_t) - p_stackval_from_data);
606                 /* load function address */
607                 ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, offs);
608                 /* call stackval_from_data */
609                 ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
610                 ARM_MOV_REG_REG(p, ARMREG_PC, ARMREG_R4);
611         }
612
613         /* store retval ptr */
614         p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R5, (armword_t)stackval_pos);
615         ARM_ADD_REG_REG(p, ARMREG_R5, ARMREG_SP, ARMREG_R4);
616         ARM_STR_IMM(p, ARMREG_R5, ARMREG_SP, MINV_OFFS(retval));
617
618         /*
619          * Call the method.
620          */
621         /* A1 = MonoInvocation ptr */
622         ARM_MOV_REG_REG(p, ARMREG_A1, ARMREG_SP);
623         offs = -(p + 2*sizeof(arminstr_t) - p_exec);
624         /* load function address */
625         ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, offs);
626         /* call ves_exec */
627         ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC);
628         ARM_MOV_REG_REG(p, ARMREG_PC, ARMREG_R4);
629
630
631         /*
632          * Move retval into reg.
633          */
634         if (sig->ret->byref) {
635                 ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
636         } else {
637                 switch (sig->ret->type) {
638                 case MONO_TYPE_BOOLEAN:
639                 case MONO_TYPE_I1:
640                 case MONO_TYPE_U1:
641                         ARM_LDRB_IMM(p, ARMREG_R0, ARMREG_R5, 0);
642                         break;
643                 case MONO_TYPE_CHAR:
644                 case MONO_TYPE_I2:
645                 case MONO_TYPE_U2:
646                         ARM_LDRH_IMM(p, ARMREG_R0, ARMREG_R5, 0);
647                         break;
648                 case MONO_TYPE_I:
649                 case MONO_TYPE_U:
650                 case MONO_TYPE_I4:
651                 case MONO_TYPE_U4:
652                 case MONO_TYPE_R4:
653                 case MONO_TYPE_OBJECT:
654                 case MONO_TYPE_CLASS:
655                 case MONO_TYPE_ARRAY:
656                 case MONO_TYPE_SZARRAY:
657                         ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
658                         break;
659                 case MONO_TYPE_I8:
660                 case MONO_TYPE_U8:
661                 case MONO_TYPE_R8:
662                         ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0);
663                         ARM_LDR_IMM(p, ARMREG_R1, ARMREG_R5, 4);
664                         break;
665                 case MONO_TYPE_VOID:
666                 default:
667                         break;
668                 }
669         }
670
671
672         p = (guchar*)arm_emit_std_epilogue((arminstr_t*)p, stack_size,
673             (1 << ARMREG_R4) |
674             (1 << ARMREG_R5) |
675             (1 << ARMREG_R6) |
676             (1 << ARMREG_R7));
677
678         flush_icache();
679
680 #ifdef ARM_DUMP_DISASM
681         _armdis_decode((arminstr_t*)code_buff, ((guint8*)p) - ((guint8*)code_buff));
682 #endif
683
684         ji = g_new0(MonoJitInfo, 1);
685         ji->method = method;
686         ji->code_size = ((guint8 *) p) - ((guint8 *) code_buff);
687         ji->code_start = (gpointer) code_buff;
688
689         mono_jit_info_table_add(mono_get_root_domain (), ji);
690
691         return code_buff;
692 }
693
694
695 /*
696  * mono_create_method_pointer () will insert a pointer to the MonoMethod
697  * so that the interp can easily get at the data: this function will retrieve 
698  * the method from the code stream.
699  */
700 MonoMethod* mono_method_pointer_get (void* code)
701 {
702         unsigned char* c = code;
703         /* check out magic number that follows unconditional branch */
704         if (c[4] == 'M' &&
705             c[5] == 'o' &&
706             c[6] == 'n' &&
707             c[7] == 'o') return ((MonoMethod**)code)[2];
708         return NULL;
709 }
710 #endif