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