static u32 regMipsToArmHelper(u32 regmips, u32 action, u32 type) { int regnum = regcache.reglist[regcache.reglist_cnt]; while( regnum != 0xFF ) { if(regcache.arm[regnum].arm_type == REG_EMPTY) { break; } regcache.reglist_cnt++; regnum = regcache.reglist[regcache.reglist_cnt]; } if( regnum == 0xFF ) { regFreeRegs(); regnum = regcache.reglist[regcache.reglist_cnt]; } regcache.arm[regnum].arm_type = type; regcache.arm[regnum].arm_islocked = true; regcache.mips[regmips].mips_ischanged = false; if( action != REG_LOADBRANCH ) { regcache.arm[regnum].arm_age = 0; regcache.arm[regnum].arm_use = 0; regcache.arm[regnum].ismapped = true; regcache.arm[regnum].mappedto = regmips; regcache.mips[regmips].ismapped = true; regcache.mips[regmips].mappedto = regnum; } else { regcache.arm[regnum].arm_age = 0; regcache.arm[regnum].arm_use = 0xFF; regcache.arm[regnum].ismapped = false; regcache.arm[regnum].mappedto = 0; if( regmips != 0 ) { ARM_LDR_IMM(ARM_POINTER, regnum, PERM_REG_1, CalcDisp(regmips)); } else { ARM_MOV_REG_IMM8(ARM_POINTER, regnum, 0); } regcache.reglist_cnt++; return regnum; } if(action == REG_LOAD) { if( regmips != 0 ) { ARM_LDR_IMM(ARM_POINTER, regcache.mips[regmips].mappedto, PERM_REG_1, CalcDisp(regmips)); } else { ARM_MOV_REG_IMM8(ARM_POINTER, regcache.mips[regmips].mappedto, 0); } } regcache.reglist_cnt++; return regnum; }
/* * 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; } } }