diff options
Diffstat (limited to 'src/arch/arm/tramp.c')
-rw-r--r-- | src/arch/arm/tramp.c | 710 |
1 files changed, 710 insertions, 0 deletions
diff --git a/src/arch/arm/tramp.c b/src/arch/arm/tramp.c new file mode 100644 index 0000000..f736c7a --- /dev/null +++ b/src/arch/arm/tramp.c @@ -0,0 +1,710 @@ +/* + * Create trampolines to invoke arbitrary functions. + * Copyright (c) 2002 Sergey Chaban <serge@wildwestsoftware.com> + * + * Contributions by Malte Hildingson + */ + +#include "arm-codegen.h" +#include "arm-dis.h" + +#if defined(_WIN32_WCE) || defined (UNDER_CE) +# include <windows.h> +#else +#include <unistd.h> +#include <sys/mman.h> +#endif + +#if !defined(PLATFORM_MACOSX) +#include <errno.h> + +#include "mono/metadata/class.h" +#include "mono/metadata/tabledefs.h" +#include "mono/interpreter/interp.h" +#include "mono/metadata/appdomain.h" + + +#if 0 +# define ARM_DUMP_DISASM 1 +#endif + +/* prototypes for private functions (to avoid compiler warnings) */ +void flush_icache (void); +void* alloc_code_buff (int num_instr); + + + +/* + * The resulting function takes the form: + * void func (void (*callme)(), void *retval, void *this_obj, stackval *arguments); + * NOTE: all args passed in ARM registers (A1-A4), + * then copied to R4-R7 (see definitions below). + */ + +#define REG_FUNC_ADDR ARMREG_R4 +#define REG_RETVAL ARMREG_R5 +#define REG_THIS ARMREG_R6 +#define REG_ARGP ARMREG_R7 + + +#define ARG_SIZE sizeof(stackval) + + + + +void flush_icache () +{ +#if defined(_WIN32) + FlushInstructionCache(GetCurrentProcess(), NULL, 0); +#else +# if 0 + asm ("mov r0, r0"); + asm ("mov r0, #0"); + asm ("mcr p15, 0, r0, c7, c7, 0"); +# else + /* TODO: use (movnv pc, rx) method */ +# endif +#endif +} + + +void* alloc_code_buff (int num_instr) +{ + void* code_buff; + int code_size = num_instr * sizeof(arminstr_t); + +#if defined(_WIN32) || defined(UNDER_CE) + int old_prot = 0; + + code_buff = malloc(code_size); + VirtualProtect(code_buff, code_size, PAGE_EXECUTE_READWRITE, &old_prot); +#else + int page_size = sysconf(_SC_PAGESIZE); + int new_code_size; + + new_code_size = code_size + page_size - 1; + code_buff = malloc(new_code_size); + code_buff = (void *) (((int) code_buff + page_size - 1) & ~(page_size - 1)); + + if (mprotect(code_buff, code_size, PROT_READ|PROT_WRITE|PROT_EXEC) != 0) { + g_critical (G_GNUC_PRETTY_FUNCTION + ": mprotect error: %s", g_strerror (errno)); + } +#endif + + return code_buff; +} + + +/* + * Refer to ARM Procedure Call Standard (APCS) for more info. + */ +MonoPIFunc mono_arch_create_trampoline (MonoMethodSignature *sig, gboolean string_ctor) +{ + MonoType* param; + MonoPIFunc code_buff; + arminstr_t* p; + guint32 code_size, stack_size; + guint32 simple_type; + int i, hasthis, aregs, regc, stack_offs; + int this_loaded; + guchar reg_alloc [ARM_NUM_ARG_REGS]; + + /* pessimistic estimation for prologue/epilogue size */ + code_size = 16 + 16; + /* push/pop work regs */ + code_size += 2; + /* call */ + code_size += 2; + /* handle retval */ + code_size += 2; + + stack_size = 0; + hasthis = sig->hasthis ? 1 : 0; + + aregs = ARM_NUM_ARG_REGS - hasthis; + + for (i = 0, regc = aregs; i < sig->param_count; ++i) { + param = sig->params [i]; + + /* keep track of argument sizes */ + if (i < ARM_NUM_ARG_REGS) reg_alloc [i] = 0; + + if (param->byref) { + if (regc > 0) { + code_size += 1; + reg_alloc [i] = regc; + --regc; + } else { + code_size += 2; + stack_size += sizeof(gpointer); + } + } else { + simple_type = param->type; +enum_calc_size: + switch (simple_type) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_R4: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + if (regc > 0) { + /* register arg */ + code_size += 1; + reg_alloc [i] = regc; + --regc; + } else { + /* stack arg */ + code_size += 2; + stack_size += 4; + } + break; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R8: + /* keep track of argument sizes */ + if (regc > 1) { + /* fits into registers, two LDRs */ + code_size += 2; + reg_alloc [i] = regc; + regc -= 2; + } else if (regc > 0) { + /* first half fits into register, one LDR */ + code_size += 1; + reg_alloc [i] = regc; + --regc; + /* the rest on the stack, LDR/STR */ + code_size += 2; + stack_size += 4; + } else { + /* stack arg, 4 instrs - 2x(LDR/STR) */ + code_size += 4; + stack_size += 2 * 4; + } + break; + case MONO_TYPE_VALUETYPE: + if (param->data.klass->enumtype) { + simple_type = param->data.klass->enum_basetype->type; + goto enum_calc_size; + } + + if (mono_class_value_size(param->data.klass, NULL) != 4) { + g_error("can only marshal enums, not generic structures (size: %d)", mono_class_value_size(param->data.klass, NULL)); + } + if (regc > 0) { + /* register arg */ + code_size += 1; + reg_alloc [i] = regc; + --regc; + } else { + /* stack arg */ + code_size += 2; + stack_size += 4; + } + break; + default : + break; + } + } + } + + code_buff = (MonoPIFunc)alloc_code_buff(code_size); + p = (arminstr_t*)code_buff; + + /* prologue */ + p = arm_emit_lean_prologue(p, stack_size, + /* save workset (r4-r7) */ + (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6) | (1 << ARMREG_R7)); + + + /* copy args into workset */ + /* callme - always present */ + ARM_MOV_REG_REG(p, ARMREG_R4, ARMREG_A1); + /* retval */ + if (sig->ret->byref || string_ctor || (sig->ret->type != MONO_TYPE_VOID)) { + ARM_MOV_REG_REG(p, ARMREG_R5, ARMREG_A2); + } + /* this_obj */ + if (sig->hasthis) { + this_loaded = 0; + if (stack_size == 0) { + ARM_MOV_REG_REG(p, ARMREG_A1, ARMREG_A3); + this_loaded = 1; + } else { + ARM_MOV_REG_REG(p, ARMREG_R6, ARMREG_A3); + } + } + /* args */ + if (sig->param_count != 0) { + ARM_MOV_REG_REG(p, ARMREG_R7, ARMREG_A4); + } + + stack_offs = stack_size; + + /* handle arguments */ + /* in reverse order so we could use r0 (arg1) for memory transfers */ + for (i = sig->param_count; --i >= 0;) { + param = sig->params [i]; + if (param->byref) { + if (i < aregs && reg_alloc[i] > 0) { + ARM_LDR_IMM(p, ARMREG_A1 + i, REG_ARGP, i*ARG_SIZE); + } else { + stack_offs -= sizeof(armword_t); + ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE); + ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs); + } + } else { + simple_type = param->type; +enum_marshal: + switch (simple_type) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_CHAR: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_R4: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_CLASS: + case MONO_TYPE_OBJECT: + case MONO_TYPE_STRING: + if (i < aregs && reg_alloc [i] > 0) { + /* pass in register */ + ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE); + } else { + stack_offs -= sizeof(armword_t); + ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE); + ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs); + } + break; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R8: + if (i < aregs && reg_alloc [i] > 0) { + if (reg_alloc [i] > 1) { + /* pass in registers */ + ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE); + ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]) + 1, REG_ARGP, i*ARG_SIZE + 4); + } else { + stack_offs -= sizeof(armword_t); + ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE + 4); + ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs); + ARM_LDR_IMM(p, ARMREG_A1 + hasthis + (aregs - reg_alloc [i]), REG_ARGP, i*ARG_SIZE); + } + } else { + /* two words transferred on the stack */ + stack_offs -= 2*sizeof(armword_t); + ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE); + ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs); + ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i*ARG_SIZE + 4); + ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs + 4); + } + break; + case MONO_TYPE_VALUETYPE: + if (param->data.klass->enumtype) { + /* it's an enum value, proceed based on its base type */ + simple_type = param->data.klass->enum_basetype->type; + goto enum_marshal; + } else { + if (i < aregs && reg_alloc[i] > 0) { + int vtreg = ARMREG_A1 + hasthis + + hasthis + (aregs - reg_alloc[i]); + ARM_LDR_IMM(p, vtreg, REG_ARGP, i * ARG_SIZE); + ARM_LDR_IMM(p, vtreg, vtreg, 0); + } else { + stack_offs -= sizeof(armword_t); + ARM_LDR_IMM(p, ARMREG_R0, REG_ARGP, i * ARG_SIZE); + ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R0, 0); + ARM_STR_IMM(p, ARMREG_R0, ARMREG_SP, stack_offs); + } + } + break; + + default: + break; + } + } + } + + if (sig->hasthis && !this_loaded) { + /* [this] always passed in A1, regardless of sig->call_convention */ + ARM_MOV_REG_REG(p, ARMREG_A1, REG_THIS); + } + + /* call [func] */ + ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC); + ARM_MOV_REG_REG(p, ARMREG_PC, REG_FUNC_ADDR); + + /* handle retval */ + if (sig->ret->byref || string_ctor) { + ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0); + } else { + simple_type = sig->ret->type; +enum_retvalue: + switch (simple_type) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + ARM_STRB_IMM(p, ARMREG_R0, REG_RETVAL, 0); + break; + case MONO_TYPE_CHAR: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + ARM_STRH_IMM(p, ARMREG_R0, REG_RETVAL, 0); + break; + /* + * A 32-bit integer and integer-equivalent return value + * is returned in R0. + * Single-precision floating-point values are returned in R0. + */ + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_R4: + case MONO_TYPE_OBJECT: + case MONO_TYPE_CLASS: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_STRING: + ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0); + break; + /* + * A 64-bit integer is returned in R0 and R1. + * Double-precision floating-point values are returned in R0 and R1. + */ + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R8: + ARM_STR_IMM(p, ARMREG_R0, REG_RETVAL, 0); + ARM_STR_IMM(p, ARMREG_R1, REG_RETVAL, 4); + break; + case MONO_TYPE_VALUETYPE: + if (sig->ret->data.klass->enumtype) { + simple_type = sig->ret->data.klass->enum_basetype->type; + goto enum_retvalue; + } + break; + case MONO_TYPE_VOID: + break; + default: + break; + } + } + + p = arm_emit_std_epilogue(p, stack_size, + /* restore R4-R7 */ + (1 << ARMREG_R4) | (1 << ARMREG_R5) | (1 << ARMREG_R6) | (1 << ARMREG_R7)); + + flush_icache(); + +#ifdef ARM_DUMP_DISASM + _armdis_decode((arminstr_t*)code_buff, ((guint8*)p) - ((guint8*)code_buff)); +#endif + + return code_buff; +} + + + +#define MINV_OFFS(member) G_STRUCT_OFFSET(MonoInvocation, member) + + + +/* + * Returns a pointer to a native function that can be used to + * call the specified method. + * The function created will receive the arguments according + * to the call convention specified in the method. + * This function works by creating a MonoInvocation structure, + * filling the fields in and calling ves_exec_method on it. + * Still need to figure out how to handle the exception stuff + * across the managed/unmanaged boundary. + */ +void* mono_arch_create_method_pointer (MonoMethod* method) +{ + MonoMethodSignature* sig; + guchar* p, * p_method, * p_stackval_from_data, * p_exec; + void* code_buff; + int i, stack_size, arg_pos, arg_add, stackval_pos, offs; + int areg, reg_args, shift, pos; + MonoJitInfo *ji; + + code_buff = alloc_code_buff(128); + p = (guchar*)code_buff; + + sig = method->signature; + + ARM_B(p, 3); + + /* embed magic number followed by method pointer */ + *p++ = 'M'; + *p++ = 'o'; + *p++ = 'n'; + *p++ = 'o'; + /* method ptr */ + *(void**)p = method; + p_method = p; + p += 4; + + /* call table */ + *(void**)p = stackval_from_data; + p_stackval_from_data = p; + p += 4; + *(void**)p = ves_exec_method; + p_exec = p; + p += 4; + + stack_size = sizeof(MonoInvocation) + ARG_SIZE*(sig->param_count + 1) + ARM_NUM_ARG_REGS*2*sizeof(armword_t); + + /* prologue */ + p = (guchar*)arm_emit_lean_prologue((arminstr_t*)p, stack_size, + (1 << ARMREG_R4) | + (1 << ARMREG_R5) | + (1 << ARMREG_R6) | + (1 << ARMREG_R7)); + + /* R7 - ptr to stack args */ + ARM_MOV_REG_REG(p, ARMREG_R7, ARMREG_IP); + + /* + * Initialize MonoInvocation fields, first the ones known now. + */ + ARM_MOV_REG_IMM8(p, ARMREG_R4, 0); + ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(ex)); + ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(ex_handler)); + ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(parent)); + + /* Set the method pointer. */ + ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, -(int)(p - p_method + sizeof(arminstr_t)*2)); + ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(method)); + + if (sig->hasthis) { + /* [this] in A1 */ + ARM_STR_IMM(p, ARMREG_A1, ARMREG_SP, MINV_OFFS(obj)); + } else { + /* else set minv.obj to NULL */ + ARM_STR_IMM(p, ARMREG_R4, ARMREG_SP, MINV_OFFS(obj)); + } + + /* copy args from registers to stack */ + areg = ARMREG_A1 + sig->hasthis; + arg_pos = -(int)(ARM_NUM_ARG_REGS - sig->hasthis) * 2 * sizeof(armword_t); + arg_add = 0; + for (i = 0; i < sig->param_count; ++i) { + if (areg >= ARM_NUM_ARG_REGS) break; + ARM_STR_IMM(p, areg, ARMREG_R7, arg_pos); + ++areg; + if (!sig->params[i]->byref) { + switch (sig->params[i]->type) { + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R8: + if (areg >= ARM_NUM_ARG_REGS) { + /* load second half of 64-bit arg */ + ARM_LDR_IMM(p, ARMREG_R4, ARMREG_R7, 0); + ARM_STR_IMM(p, ARMREG_R4, ARMREG_R7, arg_pos + sizeof(armword_t)); + arg_add = sizeof(armword_t); + } else { + /* second half is already the register */ + ARM_STR_IMM(p, areg, ARMREG_R7, arg_pos + sizeof(armword_t)); + ++areg; + } + break; + case MONO_TYPE_VALUETYPE: + /* assert */ + default: + break; + } + } + arg_pos += 2 * sizeof(armword_t); + } + /* number of args passed in registers */ + reg_args = i; + + + + /* + * Calc and save stack args ptr, + * args follow MonoInvocation struct on the stack. + */ + ARM_ADD_REG_IMM8(p, ARMREG_R1, ARMREG_SP, sizeof(MonoInvocation)); + ARM_STR_IMM(p, ARMREG_R1, ARMREG_SP, MINV_OFFS(stack_args)); + + /* convert method args to stackvals */ + arg_pos = -(int)(ARM_NUM_ARG_REGS - sig->hasthis) * 2 * sizeof(armword_t); + stackval_pos = sizeof(MonoInvocation); + for (i = 0; i < sig->param_count; ++i) { + if (i < reg_args) { + ARM_SUB_REG_IMM8(p, ARMREG_A3, ARMREG_R7, -arg_pos); + arg_pos += 2 * sizeof(armword_t); + } else { + if (arg_pos < 0) arg_pos = 0; + pos = arg_pos + arg_add; + if (pos <= 0xFF) { + ARM_ADD_REG_IMM8(p, ARMREG_A3, ARMREG_R7, pos); + } else { + if (is_arm_const((armword_t)pos)) { + shift = calc_arm_mov_const_shift((armword_t)pos); + ARM_ADD_REG_IMM(p, ARMREG_A3, ARMREG_R7, pos >> ((32 - shift) & 31), shift >> 1); + } else { + p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R6, (armword_t)pos); + ARM_ADD_REG_REG(p, ARMREG_A2, ARMREG_R7, ARMREG_R6); + } + } + arg_pos += sizeof(armword_t); + if (!sig->params[i]->byref) { + switch (sig->params[i]->type) { + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R8: + arg_pos += sizeof(armword_t); + break; + case MONO_TYPE_VALUETYPE: + /* assert */ + default: + break; + } + } + } + + /* A2 = result */ + if (stackval_pos <= 0xFF) { + ARM_ADD_REG_IMM8(p, ARMREG_A2, ARMREG_SP, stackval_pos); + } else { + if (is_arm_const((armword_t)stackval_pos)) { + shift = calc_arm_mov_const_shift((armword_t)stackval_pos); + ARM_ADD_REG_IMM(p, ARMREG_A2, ARMREG_SP, stackval_pos >> ((32 - shift) & 31), shift >> 1); + } else { + p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R6, (armword_t)stackval_pos); + ARM_ADD_REG_REG(p, ARMREG_A2, ARMREG_SP, ARMREG_R6); + } + } + + /* A1 = type */ + p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_A1, (armword_t)sig->params [i]); + + stackval_pos += ARG_SIZE; + + offs = -(p + 2*sizeof(arminstr_t) - p_stackval_from_data); + /* load function address */ + ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, offs); + /* call stackval_from_data */ + ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC); + ARM_MOV_REG_REG(p, ARMREG_PC, ARMREG_R4); + } + + /* store retval ptr */ + p = (guchar*)arm_mov_reg_imm32((arminstr_t*)p, ARMREG_R5, (armword_t)stackval_pos); + ARM_ADD_REG_REG(p, ARMREG_R5, ARMREG_SP, ARMREG_R4); + ARM_STR_IMM(p, ARMREG_R5, ARMREG_SP, MINV_OFFS(retval)); + + /* + * Call the method. + */ + /* A1 = MonoInvocation ptr */ + ARM_MOV_REG_REG(p, ARMREG_A1, ARMREG_SP); + offs = -(p + 2*sizeof(arminstr_t) - p_exec); + /* load function address */ + ARM_LDR_IMM(p, ARMREG_R4, ARMREG_PC, offs); + /* call ves_exec */ + ARM_MOV_REG_REG(p, ARMREG_LR, ARMREG_PC); + ARM_MOV_REG_REG(p, ARMREG_PC, ARMREG_R4); + + + /* + * Move retval into reg. + */ + if (sig->ret->byref) { + ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0); + } else { + switch (sig->ret->type) { + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_I1: + case MONO_TYPE_U1: + ARM_LDRB_IMM(p, ARMREG_R0, ARMREG_R5, 0); + break; + case MONO_TYPE_CHAR: + case MONO_TYPE_I2: + case MONO_TYPE_U2: + ARM_LDRH_IMM(p, ARMREG_R0, ARMREG_R5, 0); + break; + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_R4: + case MONO_TYPE_OBJECT: + case MONO_TYPE_CLASS: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0); + break; + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R8: + ARM_LDR_IMM(p, ARMREG_R0, ARMREG_R5, 0); + ARM_LDR_IMM(p, ARMREG_R1, ARMREG_R5, 4); + break; + case MONO_TYPE_VOID: + default: + break; + } + } + + + p = (guchar*)arm_emit_std_epilogue((arminstr_t*)p, stack_size, + (1 << ARMREG_R4) | + (1 << ARMREG_R5) | + (1 << ARMREG_R6) | + (1 << ARMREG_R7)); + + flush_icache(); + +#ifdef ARM_DUMP_DISASM + _armdis_decode((arminstr_t*)code_buff, ((guint8*)p) - ((guint8*)code_buff)); +#endif + + ji = g_new0(MonoJitInfo, 1); + ji->method = method; + ji->code_size = ((guint8 *) p) - ((guint8 *) code_buff); + ji->code_start = (gpointer) code_buff; + + mono_jit_info_table_add(mono_get_root_domain (), ji); + + return code_buff; +} + + +/* + * mono_create_method_pointer () will insert a pointer to the MonoMethod + * so that the interp can easily get at the data: this function will retrieve + * the method from the code stream. + */ +MonoMethod* mono_method_pointer_get (void* code) +{ + unsigned char* c = code; + /* check out magic number that follows unconditional branch */ + if (c[4] == 'M' && + c[5] == 'o' && + c[6] == 'n' && + c[7] == 'o') return ((MonoMethod**)code)[2]; + return NULL; +} +#endif |