diff -r 78af2a4d1ec3 -r 0cc8699f7372 hotspot/src/cpu/aarch64/vm/aarch64_call.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/cpu/aarch64/vm/aarch64_call.cpp Tue Jan 20 11:34:17 2015 -0800 @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2014, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifdef BUILTIN_SIM + +#include +#include +#include "asm/macroAssembler.hpp" +#include "asm/macroAssembler.inline.hpp" +#include "runtime/sharedRuntime.hpp" +#include "../../../../../../simulator/cpustate.hpp" +#include "../../../../../../simulator/simulator.hpp" + +/* + * a routine to initialise and enter ARM simulator execution when + * calling into ARM code from x86 code. + * + * we maintain a simulator per-thread and provide it with 8 Mb of + * stack space + */ +#define SIM_STACK_SIZE (1024 * 1024) // in units of u_int64_t + +extern "C" u_int64_t get_alt_stack() +{ + return AArch64Simulator::altStack(); +} + +extern "C" void setup_arm_sim(void *sp, u_int64_t calltype) +{ + // n.b. this function runs on the simulator stack so as to avoid + // simulator frames appearing in between VM x86 and ARM frames. note + // that arfgument sp points to the old (VM) stack from which the + // call into the sim was made. The stack switch and entry into this + // routine is handled by x86 prolog code planted in the head of the + // ARM code buffer which the sim is about to start executing (see + // aarch64_linkage.S). + // + // The first ARM instruction in the buffer is identified by fnptr + // stored at the top of the old stack. x86 register contents precede + // fnptr. preceding that are the fp and return address of the VM + // caller into ARM code. any extra, non-register arguments passed to + // the linkage routine precede the fp (this is as per any normal x86 + // call wirth extra args). + // + // note that the sim creates Java frames on the Java stack just + // above sp (i.e. directly above fnptr). it sets the sim FP register + // to the pushed fp for the caller effectively eliding the register + // data saved by the linkage routine. + // + // x86 register call arguments are loaded from the stack into ARM + // call registers. if extra arguments occur preceding the x86 + // caller's fp then they are copied either into extra ARM registers + // (ARM has 8 rather than 6 gp call registers) or up the stack + // beyond the saved x86 registers so that they immediately precede + // the ARM frame where the ARM calling convention expects them to + // be. + // + // n.b. the number of register/stack values passed to the ARM code + // is determined by calltype + // + // +--------+ + // | fnptr | <--- argument sp points here + // +--------+ | + // | rax | | return slot if we need to return a value + // +--------+ | + // | rdi | increasing + // +--------+ address + // | rsi | | + // +--------+ V + // | rdx | + // +--------+ + // | rcx | + // +--------+ + // | r8 | + // +--------+ + // | r9 | + // +--------+ + // | xmm0 | + // +--------+ + // | xmm1 | + // +--------+ + // | xmm2 | + // +--------+ + // | xmm3 | + // +--------+ + // | xmm4 | + // +--------+ + // | xmm5 | + // +--------+ + // | xmm6 | + // +--------+ + // | xmm7 | + // +--------+ + // | fp | + // +--------+ + // | caller | + // | ret ip | + // +--------+ + // | arg0 | <-- any extra call args start here + // +--------+ offset = 18 * wordSize + // | . . . | (i.e. 1 * calladdr + 1 * rax + 6 * gp call regs + // + 8 * fp call regs + 2 * frame words) + // + // we use a unique sim/stack per thread + const int cursor2_offset = 18; + const int fp_offset = 16; + u_int64_t *cursor = (u_int64_t *)sp; + u_int64_t *cursor2 = ((u_int64_t *)sp) + cursor2_offset; + u_int64_t *fp = ((u_int64_t *)sp) + fp_offset; + int gp_arg_count = calltype & 0xf; + int fp_arg_count = (calltype >> 4) & 0xf; + int return_type = (calltype >> 8) & 0x3; + AArch64Simulator *sim = AArch64Simulator::get_current(UseSimulatorCache, DisableBCCheck); + // save previous cpu state in case this is a recursive entry + CPUState saveState = sim->getCPUState(); + // set up initial sim pc, sp and fp registers + sim->init(*cursor++, (u_int64_t)sp, (u_int64_t)fp); + u_int64_t *return_slot = cursor++; + + // if we need to pass the sim extra args on the stack then bump + // the stack pointer now + u_int64_t *cursor3 = (u_int64_t *)sim->getCPUState().xreg(SP, 1); + if (gp_arg_count > 8) { + cursor3 -= gp_arg_count - 8; + } + if (fp_arg_count > 8) { + cursor3 -= fp_arg_count - 8; + } + sim->getCPUState().xreg(SP, 1) = (u_int64_t)(cursor3++); + + for (int i = 0; i < gp_arg_count; i++) { + if (i < 6) { + // copy saved register to sim register + GReg reg = (GReg)i; + sim->getCPUState().xreg(reg, 0) = *cursor++; + } else if (i < 8) { + // copy extra int arg to sim register + GReg reg = (GReg)i; + sim->getCPUState().xreg(reg, 0) = *cursor2++; + } else { + // copy extra fp arg to sim stack + *cursor3++ = *cursor2++; + } + } + for (int i = 0; i < fp_arg_count; i++) { + if (i < 8) { + // copy saved register to sim register + GReg reg = (GReg)i; + sim->getCPUState().xreg(reg, 0) = *cursor++; + } else { + // copy extra arg to sim stack + *cursor3++ = *cursor2++; + } + } + AArch64Simulator::status_t return_status = sim->run(); + if (return_status != AArch64Simulator::STATUS_RETURN){ + sim->simPrint0(); + fatal("invalid status returned from simulator.run()\n"); + } + switch (return_type) { + case MacroAssembler::ret_type_void: + default: + break; + case MacroAssembler::ret_type_integral: + // this overwrites the saved r0 + *return_slot = sim->getCPUState().xreg(R0, 0); + break; + case MacroAssembler::ret_type_float: + *(float *)return_slot = sim->getCPUState().sreg(V0); + break; + case MacroAssembler::ret_type_double: + *(double *)return_slot = sim->getCPUState().dreg(V0); + break; + } + // restore incoimng cpu state + sim->getCPUState() = saveState; +} + +#endif