/*
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. 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.
*
*/
#include "precompiled.hpp"
#include "asm/assembler.hpp"
#include "asm/assembler.inline.hpp"
#include "compiler/compiler_globals.hpp"
#include "compiler/disassembler.hpp"
#include "crc32c.h"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "gc/shared/tlab_globals.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm.h"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/accessDecorators.hpp"
#include "oops/compressedOops.inline.hpp"
#include "oops/klass.inline.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/continuation.hpp"
#include "runtime/flags/flagSetting.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/objectMonitor.hpp"
#include "runtime/os.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/safepointMechanism.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
#include "utilities/macros.hpp"
#ifdef PRODUCT
#define BLOCK_COMMENT(str) /* nothing */
#define STOP(error) stop(error)
#else
#define BLOCK_COMMENT(str) block_comment(str)
#define STOP(error) block_comment(error); stop(error)
#endif
#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
#ifdef ASSERT
bool AbstractAssembler::pd_check_instruction_mark() { return true; }
#endif
static Assembler::Condition reverse[] = {
Assembler::noOverflow /* overflow = 0x0 */ ,
Assembler::overflow /* noOverflow = 0x1 */ ,
Assembler::aboveEqual /* carrySet = 0x2, below = 0x2 */ ,
Assembler::below /* aboveEqual = 0x3, carryClear = 0x3 */ ,
Assembler::notZero /* zero = 0x4, equal = 0x4 */ ,
Assembler::zero /* notZero = 0x5, notEqual = 0x5 */ ,
Assembler::above /* belowEqual = 0x6 */ ,
Assembler::belowEqual /* above = 0x7 */ ,
Assembler::positive /* negative = 0x8 */ ,
Assembler::negative /* positive = 0x9 */ ,
Assembler::noParity /* parity = 0xa */ ,
Assembler::parity /* noParity = 0xb */ ,
Assembler::greaterEqual /* less = 0xc */ ,
Assembler::less /* greaterEqual = 0xd */ ,
Assembler::greater /* lessEqual = 0xe */ ,
Assembler::lessEqual /* greater = 0xf, */
};
// Implementation of MacroAssembler
// First all the versions that have distinct versions depending on 32/64 bit
// Unless the difference is trivial (1 line or so).
#ifndef _LP64
// 32bit versions
Address MacroAssembler::as_Address(AddressLiteral adr) {
return Address(adr.target(), adr.rspec());
}
Address MacroAssembler::as_Address(ArrayAddress adr, Register rscratch) {
assert(rscratch == noreg, "");
return Address::make_array(adr);
}
void MacroAssembler::call_VM_leaf_base(address entry_point,
int number_of_arguments) {
call(RuntimeAddress(entry_point));
increment(rsp, number_of_arguments * wordSize);
}
void MacroAssembler::cmpklass(Address src1, Metadata* obj) {
cmp_literal32(src1, (int32_t)obj, metadata_Relocation::spec_for_immediate());
}
void MacroAssembler::cmpklass(Register src1, Metadata* obj) {
cmp_literal32(src1, (int32_t)obj, metadata_Relocation::spec_for_immediate());
}
void MacroAssembler::cmpoop(Address src1, jobject obj) {
cmp_literal32(src1, (int32_t)obj, oop_Relocation::spec_for_immediate());
}
void MacroAssembler::cmpoop(Register src1, jobject obj, Register rscratch) {
assert(rscratch == noreg, "redundant");
cmp_literal32(src1, (int32_t)obj, oop_Relocation::spec_for_immediate());
}
void MacroAssembler::extend_sign(Register hi, Register lo) {
// According to Intel Doc. AP-526, "Integer Divide", p.18.
if (VM_Version::is_P6() && hi == rdx && lo == rax) {
cdql();
} else {
movl(hi, lo);
sarl(hi, 31);
}
}
void MacroAssembler::jC2(Register tmp, Label& L) {
// set parity bit if FPU flag C2 is set (via rax)
save_rax(tmp);
fwait(); fnstsw_ax();
sahf();
restore_rax(tmp);
// branch
jcc(Assembler::parity, L);
}
void MacroAssembler::jnC2(Register tmp, Label& L) {
// set parity bit if FPU flag C2 is set (via rax)
save_rax(tmp);
fwait(); fnstsw_ax();
sahf();
restore_rax(tmp);
// branch
jcc(Assembler::noParity, L);
}
// 32bit can do a case table jump in one instruction but we no longer allow the base
// to be installed in the Address class
void MacroAssembler::jump(ArrayAddress entry, Register rscratch) {
assert(rscratch == noreg, "not needed");
jmp(as_Address(entry, noreg));
}
// Note: y_lo will be destroyed
void MacroAssembler::lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo) {
// Long compare for Java (semantics as described in JVM spec.)
Label high, low, done;
cmpl(x_hi, y_hi);
jcc(Assembler::less, low);
jcc(Assembler::greater, high);
// x_hi is the return register
xorl(x_hi, x_hi);
cmpl(x_lo, y_lo);
jcc(Assembler::below, low);
jcc(Assembler::equal, done);
bind(high);
xorl(x_hi, x_hi);
increment(x_hi);
jmp(done);
bind(low);
xorl(x_hi, x_hi);
decrementl(x_hi);
bind(done);
}
void MacroAssembler::lea(Register dst, AddressLiteral src) {
mov_literal32(dst, (int32_t)src.target(), src.rspec());
}
void MacroAssembler::lea(Address dst, AddressLiteral adr, Register rscratch) {
assert(rscratch == noreg, "not needed");
// leal(dst, as_Address(adr));
// see note in movl as to why we must use a move
mov_literal32(dst, (int32_t)adr.target(), adr.rspec());
}
void MacroAssembler::leave() {
mov(rsp, rbp);
pop(rbp);
}
void MacroAssembler::lmul(int x_rsp_offset, int y_rsp_offset) {
// Multiplication of two Java long values stored on the stack
// as illustrated below. Result is in rdx:rax.
//
// rsp ---> [ ?? ] \ \
// .... | y_rsp_offset |
// [ y_lo ] / (in bytes) | x_rsp_offset
// [ y_hi ] | (in bytes)
// .... |
// [ x_lo ] /
// [ x_hi ]
// ....
//
// Basic idea: lo(result) = lo(x_lo * y_lo)
// hi(result) = hi(x_lo * y_lo) + lo(x_hi * y_lo) + lo(x_lo * y_hi)
Address x_hi(rsp, x_rsp_offset + wordSize); Address x_lo(rsp, x_rsp_offset);
Address y_hi(rsp, y_rsp_offset + wordSize); Address y_lo(rsp, y_rsp_offset);
Label quick;
// load x_hi, y_hi and check if quick
// multiplication is possible
movl(rbx, x_hi);
movl(rcx, y_hi);
movl(rax, rbx);
orl(rbx, rcx); // rbx, = 0 <=> x_hi = 0 and y_hi = 0
jcc(Assembler::zero, quick); // if rbx, = 0 do quick multiply
// do full multiplication
// 1st step
mull(y_lo); // x_hi * y_lo
movl(rbx, rax); // save lo(x_hi * y_lo) in rbx,
// 2nd step
movl(rax, x_lo);
mull(rcx); // x_lo * y_hi
addl(rbx, rax); // add lo(x_lo * y_hi) to rbx,
// 3rd step
bind(quick); // note: rbx, = 0 if quick multiply!
movl(rax, x_lo);
mull(y_lo); // x_lo * y_lo
addl(rdx, rbx); // correct hi(x_lo * y_lo)
}
void MacroAssembler::lneg(Register hi, Register lo) {
negl(lo);
adcl(hi, 0);
negl(hi);
}
void MacroAssembler::lshl(Register hi, Register lo) {
// Java shift left long support (semantics as described in JVM spec., p.305)
// (basic idea for shift counts s >= n: x << s == (x << n) << (s - n))
// shift value is in rcx !
assert(hi != rcx, "must not use rcx");
assert(lo != rcx, "must not use rcx");
const Register s = rcx; // shift count
const int n = BitsPerWord;
Label L;
andl(s, 0x3f); // s := s & 0x3f (s < 0x40)
cmpl(s, n); // if (s < n)
jcc(Assembler::less, L); // else (s >= n)
movl(hi, lo); // x := x << n
xorl(lo, lo);
// Note: subl(s, n) is not needed since the Intel shift instructions work rcx mod n!
bind(L); // s (mod n) < n
shldl(hi, lo); // x := x << s
shll(lo);
}
void MacroAssembler::lshr(Register hi, Register lo, bool sign_extension) {
// Java shift right long support (semantics as described in JVM spec., p.306 & p.310)
// (basic idea for shift counts s >= n: x >> s == (x >> n) >> (s - n))
assert(hi != rcx, "must not use rcx");
assert(lo != rcx, "must not use rcx");
const Register s = rcx; // shift count
const int n = BitsPerWord;
Label L;
andl(s, 0x3f); // s := s & 0x3f (s < 0x40)
cmpl(s, n); // if (s < n)
jcc(Assembler::less, L); // else (s >= n)
movl(lo, hi); // x := x >> n
if (sign_extension) sarl(hi, 31);
else xorl(hi, hi);
// Note: subl(s, n) is not needed since the Intel shift instructions work rcx mod n!
bind(L); // s (mod n) < n
shrdl(lo, hi); // x := x >> s
if (sign_extension) sarl(hi);
else shrl(hi);
}
void MacroAssembler::movoop(Register dst, jobject obj) {
mov_literal32(dst, (int32_t)obj, oop_Relocation::spec_for_immediate());
}
void MacroAssembler::movoop(Address dst, jobject obj, Register rscratch) {
assert(rscratch == noreg, "redundant");
mov_literal32(dst, (int32_t)obj, oop_Relocation::spec_for_immediate());
}
void MacroAssembler::mov_metadata(Register dst, Metadata* obj) {
mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate());
}
void MacroAssembler::mov_metadata(Address dst, Metadata* obj, Register rscratch) {
assert(rscratch == noreg, "redundant");
mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate());
}
void MacroAssembler::movptr(Register dst, AddressLiteral src) {
if (src.is_lval()) {
mov_literal32(dst, (intptr_t)src.target(), src.rspec());
} else {
movl(dst, as_Address(src));
}
}
void MacroAssembler::movptr(ArrayAddress dst, Register src, Register rscratch) {
assert(rscratch == noreg, "redundant");
movl(as_Address(dst, noreg), src);
}
void MacroAssembler::movptr(Register dst, ArrayAddress src) {
movl(dst, as_Address(src, noreg));
}
void MacroAssembler::movptr(Address dst, intptr_t src, Register rscratch) {
assert(rscratch == noreg, "redundant");
movl(dst, src);
}
void MacroAssembler::pushoop(jobject obj, Register rscratch) {
assert(rscratch == noreg, "redundant");
push_literal32((int32_t)obj, oop_Relocation::spec_for_immediate());
}
void MacroAssembler::pushklass(Metadata* obj, Register rscratch) {
assert(rscratch == noreg, "redundant");
push_literal32((int32_t)obj, metadata_Relocation::spec_for_immediate());
}
void MacroAssembler::pushptr(AddressLiteral src, Register rscratch) {
assert(rscratch == noreg, "redundant");
if (src.is_lval()) {
push_literal32((int32_t)src.target(), src.rspec());
} else {
pushl(as_Address(src));
}
}
static void pass_arg0(MacroAssembler* masm, Register arg) {
masm->push(arg);
}
static void pass_arg1(MacroAssembler* masm, Register arg) {
masm->push(arg);
}
static void pass_arg2(MacroAssembler* masm, Register arg) {
masm->push(arg);
}
static void pass_arg3(MacroAssembler* masm, Register arg) {
masm->push(arg);
}
#ifndef PRODUCT
extern "C" void findpc(intptr_t x);
#endif
void MacroAssembler::debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip, char* msg) {
// In order to get locks to work, we need to fake a in_VM state
JavaThread* thread = JavaThread::current();
JavaThreadState saved_state = thread->thread_state();
thread->set_thread_state(_thread_in_vm);
if (ShowMessageBoxOnError) {
JavaThread* thread = JavaThread::current();
JavaThreadState saved_state = thread->thread_state();
thread->set_thread_state(_thread_in_vm);
if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
ttyLocker ttyl;
BytecodeCounter::print();
}
// To see where a verify_oop failed, get $ebx+40/X for this frame.
// This is the value of eip which points to where verify_oop will return.
if (os::message_box(msg, "Execution stopped, print registers?")) {
print_state32(rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, eip);
BREAKPOINT;
}
}
fatal("DEBUG MESSAGE: %s", msg);
}
void MacroAssembler::print_state32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip) {
ttyLocker ttyl;
FlagSetting fs(Debugging, true);
tty->print_cr("eip = 0x%08x", eip);
#ifndef PRODUCT
if ((WizardMode || Verbose) && PrintMiscellaneous) {
tty->cr();
findpc(eip);
tty->cr();
}
#endif
#define PRINT_REG(rax) \
{ tty->print("%s = ", #rax); os::print_location(tty, rax); }
PRINT_REG(rax);
PRINT_REG(rbx);
PRINT_REG(rcx);
PRINT_REG(rdx);
PRINT_REG(rdi);
PRINT_REG(rsi);
PRINT_REG(rbp);
PRINT_REG(rsp);
#undef PRINT_REG
// Print some words near top of staack.
int* dump_sp = (int*) rsp;
for (int col1 = 0; col1 < 8; col1++) {
tty->print("(rsp+0x%03x) 0x%08x: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp);
os::print_location(tty, *dump_sp++);
}
for (int row = 0; row < 16; row++) {
tty->print("(rsp+0x%03x) 0x%08x: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp);
for (int col = 0; col < 8; col++) {
tty->print(" 0x%08x", *dump_sp++);
}
tty->cr();
}
// Print some instructions around pc:
Disassembler::decode((address)eip-64, (address)eip);
tty->print_cr("--------");
Disassembler::decode((address)eip, (address)eip+32);
}
void MacroAssembler::stop(const char* msg) {
// push address of message
ExternalAddress message((address)msg);
pushptr(message.addr(), noreg);
{ Label L; call(L, relocInfo::none); bind(L); } // push eip
pusha(); // push registers
call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug32)));
hlt();
}
void MacroAssembler::warn(const char* msg) {
push_CPU_state();
// push address of message
ExternalAddress message((address)msg);
pushptr(message.addr(), noreg);
call(RuntimeAddress(CAST_FROM_FN_PTR(address, warning)));
addl(rsp, wordSize); // discard argument
pop_CPU_state();
}
void MacroAssembler::print_state() {
{ Label L; call(L, relocInfo::none); bind(L); } // push eip
pusha(); // push registers
push_CPU_state();
call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::print_state32)));
pop_CPU_state();
popa();
addl(rsp, wordSize);
}
#else // _LP64
// 64 bit versions
Address MacroAssembler::as_Address(AddressLiteral adr) {
// amd64 always does this as a pc-rel
// we can be absolute or disp based on the instruction type
// jmp/call are displacements others are absolute
assert(!adr.is_lval(), "must be rval");
assert(reachable(adr), "must be");
return Address(checked_cast<int32_t>(adr.target() - pc()), adr.target(), adr.reloc());
}
Address MacroAssembler::as_Address(ArrayAddress adr, Register rscratch) {
AddressLiteral base = adr.base();
lea(rscratch, base);
Address index = adr.index();
assert(index._disp == 0, "must not have disp"); // maybe it can?
Address array(rscratch, index._index, index._scale, index._disp);
return array;
}
void MacroAssembler::call_VM_leaf_base(address entry_point, int num_args) {
Label L, E;
#ifdef _WIN64
// Windows always allocates space for it's register args
assert(num_args <= 4, "only register arguments supported");
subq(rsp, frame::arg_reg_save_area_bytes);
#endif
// Align stack if necessary
testl(rsp, 15);
jcc(Assembler::zero, L);
subq(rsp, 8);
call(RuntimeAddress(entry_point));
addq(rsp, 8);
jmp(E);
bind(L);
call(RuntimeAddress(entry_point));
bind(E);
#ifdef _WIN64
// restore stack pointer
addq(rsp, frame::arg_reg_save_area_bytes);
#endif
}
void MacroAssembler::cmp64(Register src1, AddressLiteral src2, Register rscratch) {
assert(!src2.is_lval(), "should use cmpptr");
assert(rscratch != noreg || always_reachable(src2), "missing");
if (reachable(src2)) {
cmpq(src1, as_Address(src2));
} else {
lea(rscratch, src2);
Assembler::cmpq(src1, Address(rscratch, 0));
}
}
int MacroAssembler::corrected_idivq(Register reg) {
// Full implementation of Java ldiv and lrem; checks for special
// case as described in JVM spec., p.243 & p.271. The function
// returns the (pc) offset of the idivl instruction - may be needed
// for implicit exceptions.
//
// normal case special case
//
// input : rax: dividend min_long
// reg: divisor (may not be eax/edx) -1
//
// output: rax: quotient (= rax idiv reg) min_long
// rdx: remainder (= rax irem reg) 0
assert(reg != rax && reg != rdx, "reg cannot be rax or rdx register");
static const int64_t min_long = 0x8000000000000000;
Label normal_case, special_case;
// check for special case
cmp64(rax, ExternalAddress((address) &min_long), rdx /*rscratch*/);
jcc(Assembler::notEqual, normal_case);
xorl(rdx, rdx); // prepare rdx for possible special case (where
// remainder = 0)
cmpq(reg, -1);
jcc(Assembler::equal, special_case);
// handle normal case
bind(normal_case);
cdqq();
int idivq_offset = offset();
idivq(reg);
// normal and special case exit
bind(special_case);
return idivq_offset;
}
void MacroAssembler::decrementq(Register reg, int value) {
if (value == min_jint) { subq(reg, value); return; }
if (value < 0) { incrementq(reg, -value); return; }
if (value == 0) { ; return; }
if (value == 1 && UseIncDec) { decq(reg) ; return; }
/* else */ { subq(reg, value) ; return; }
}
void MacroAssembler::decrementq(Address dst, int value) {
if (value == min_jint) { subq(dst, value); return; }
if (value < 0) { incrementq(dst, -value); return; }
if (value == 0) { ; return; }
if (value == 1 && UseIncDec) { decq(dst) ; return; }
/* else */ { subq(dst, value) ; return; }
}
void MacroAssembler::incrementq(AddressLiteral dst, Register rscratch) {
assert(rscratch != noreg || always_reachable(dst), "missing");
if (reachable(dst)) {
incrementq(as_Address(dst));
} else {
lea(rscratch, dst);
incrementq(Address(rscratch, 0));
}
}
void MacroAssembler::incrementq(Register reg, int value) {
if (value == min_jint) { addq(reg, value); return; }
if (value < 0) { decrementq(reg, -value); return; }
if (value == 0) { ; return; }
if (value == 1 && UseIncDec) { incq(reg) ; return; }
/* else */ { addq(reg, value) ; return; }
}
void MacroAssembler::incrementq(Address dst, int value) {
if (value == min_jint) { addq(dst, value); return; }
if (value < 0) { decrementq(dst, -value); return; }
if (value == 0) { ; return; }
if (value == 1 && UseIncDec) { incq(dst) ; return; }
/* else */ { addq(dst, value) ; return; }
}
// 32bit can do a case table jump in one instruction but we no longer allow the base
// to be installed in the Address class
void MacroAssembler::jump(ArrayAddress entry, Register rscratch) {
lea(rscratch, entry.base());
Address dispatch = entry.index();
assert(dispatch._base == noreg, "must be");
dispatch._base = rscratch;
jmp(dispatch);
}
void MacroAssembler::lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo) {
ShouldNotReachHere(); // 64bit doesn't use two regs
cmpq(x_lo, y_lo);
}
void MacroAssembler::lea(Register dst, AddressLiteral src) {
mov_literal64(dst, (intptr_t)src.target(), src.rspec());
}
void MacroAssembler::lea(Address dst, AddressLiteral adr, Register rscratch) {
lea(rscratch, adr);
movptr(dst, rscratch);
}
void MacroAssembler::leave() {
// %%% is this really better? Why not on 32bit too?
emit_int8((unsigned char)0xC9); // LEAVE
}
void MacroAssembler::lneg(Register hi, Register lo) {
ShouldNotReachHere(); // 64bit doesn't use two regs
negq(lo);
}
void MacroAssembler::movoop(Register dst, jobject obj) {
mov_literal64(dst, (intptr_t)obj, oop_Relocation::spec_for_immediate());
}
void MacroAssembler::movoop(Address dst, jobject obj, Register rscratch) {
mov_literal64(rscratch, (intptr_t)obj, oop_Relocation::spec_for_immediate());
movq(dst, rscratch);
}
void MacroAssembler::mov_metadata(Register dst, Metadata* obj) {
mov_literal64(dst, (intptr_t)obj, metadata_Relocation::spec_for_immediate());
}
void MacroAssembler::mov_metadata(Address dst, Metadata* obj, Register rscratch) {
mov_literal64(rscratch, (intptr_t)obj, metadata_Relocation::spec_for_immediate());
movq(dst, rscratch);
}
void MacroAssembler::movptr(Register dst, AddressLiteral src) {
if (src.is_lval()) {
mov_literal64(dst, (intptr_t)src.target(), src.rspec());
} else {
if (reachable(src)) {
movq(dst, as_Address(src));
} else {
lea(dst, src);
movq(dst, Address(dst, 0));
}
}
}
void MacroAssembler::movptr(ArrayAddress dst, Register src, Register rscratch) {
movq(as_Address(dst, rscratch), src);
}
void MacroAssembler::movptr(Register dst, ArrayAddress src) {
movq(dst, as_Address(src, dst /*rscratch*/));
}
// src should NEVER be a real pointer. Use AddressLiteral for true pointers
void MacroAssembler::movptr(Address dst, intptr_t src, Register rscratch) {
if (is_simm32(src)) {
movptr(dst, checked_cast<int32_t>(src));
} else {
mov64(rscratch, src);
movq(dst, rscratch);
}
}
void MacroAssembler::pushoop(jobject obj, Register rscratch) {
movoop(rscratch, obj);
push(rscratch);
}
void MacroAssembler::pushklass(Metadata* obj, Register rscratch) {
mov_metadata(rscratch, obj);
push(rscratch);
}
void MacroAssembler::pushptr(AddressLiteral src, Register rscratch) {
lea(rscratch, src);
if (src.is_lval()) {
push(rscratch);
} else {
pushq(Address(rscratch, 0));
}
}
void MacroAssembler::reset_last_Java_frame(bool clear_fp) {
reset_last_Java_frame(r15_thread, clear_fp);
}
void MacroAssembler::set_last_Java_frame(Register last_java_sp,
Register last_java_fp,
address last_java_pc,
Register rscratch) {
set_last_Java_frame(r15_thread, last_java_sp, last_java_fp, last_java_pc, rscratch);
}
static void pass_arg0(MacroAssembler* masm, Register arg) {
if (c_rarg0 != arg ) {
masm->mov(c_rarg0, arg);
}
}
static void pass_arg1(MacroAssembler* masm, Register arg) {
if (c_rarg1 != arg ) {
masm->mov(c_rarg1, arg);
}
}
static void pass_arg2(MacroAssembler* masm, Register arg) {
if (c_rarg2 != arg ) {
masm->mov(c_rarg2, arg);
}
}
static void pass_arg3(MacroAssembler* masm, Register arg) {
if (c_rarg3 != arg ) {
masm->mov(c_rarg3, arg);
}
}
void MacroAssembler::stop(const char* msg) {
if (ShowMessageBoxOnError) {
address rip = pc();
pusha(); // get regs on stack
lea(c_rarg1, InternalAddress(rip));
movq(c_rarg2, rsp); // pass pointer to regs array
}
lea(c_rarg0, ExternalAddress((address) msg));
andq(rsp, -16); // align stack as required by ABI
call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64)));
hlt();
}
void MacroAssembler::warn(const char* msg) {
push(rbp);
movq(rbp, rsp);
andq(rsp, -16); // align stack as required by push_CPU_state and call
push_CPU_state(); // keeps alignment at 16 bytes
lea(c_rarg0, ExternalAddress((address) msg));
call(RuntimeAddress(CAST_FROM_FN_PTR(address, warning)));
pop_CPU_state();
mov(rsp, rbp);
pop(rbp);
}
void MacroAssembler::print_state() {
address rip = pc();
pusha(); // get regs on stack
push(rbp);
movq(rbp, rsp);
andq(rsp, -16); // align stack as required by push_CPU_state and call
push_CPU_state(); // keeps alignment at 16 bytes
lea(c_rarg0, InternalAddress(rip));
lea(c_rarg1, Address(rbp, wordSize)); // pass pointer to regs array
call_VM_leaf(CAST_FROM_FN_PTR(address, MacroAssembler::print_state64), c_rarg0, c_rarg1);
pop_CPU_state();
mov(rsp, rbp);
pop(rbp);
popa();
}
#ifndef PRODUCT
extern "C" void findpc(intptr_t x);
#endif
void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) {
// In order to get locks to work, we need to fake a in_VM state
if (ShowMessageBoxOnError) {
JavaThread* thread = JavaThread::current();
JavaThreadState saved_state = thread->thread_state();
thread->set_thread_state(_thread_in_vm);
#ifndef PRODUCT
if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
ttyLocker ttyl;
BytecodeCounter::print();
}
#endif
// To see where a verify_oop failed, get $ebx+40/X for this frame.
// XXX correct this offset for amd64
// This is the value of eip which points to where verify_oop will return.
if (os::message_box(msg, "Execution stopped, print registers?")) {
print_state64(pc, regs);
BREAKPOINT;
}
}
fatal("DEBUG MESSAGE: %s", msg);
}
void MacroAssembler::print_state64(int64_t pc, int64_t regs[]) {
ttyLocker ttyl;
FlagSetting fs(Debugging, true);
tty->print_cr("rip = 0x%016lx", (intptr_t)pc);
#ifndef PRODUCT
tty->cr();
findpc(pc);
tty->cr();
#endif
#define PRINT_REG(rax, value) \
{ tty->print("%s = ", #rax); os::print_location(tty, value); }
PRINT_REG(rax, regs[15]);
PRINT_REG(rbx, regs[12]);
PRINT_REG(rcx, regs[14]);
PRINT_REG(rdx, regs[13]);
PRINT_REG(rdi, regs[8]);
PRINT_REG(rsi, regs[9]);
PRINT_REG(rbp, regs[10]);
// rsp is actually not stored by pusha(), compute the old rsp from regs (rsp after pusha): regs + 16 = old rsp
PRINT_REG(rsp, (intptr_t)(®s[16]));
PRINT_REG(r8 , regs[7]);
PRINT_REG(r9 , regs[6]);
PRINT_REG(r10, regs[5]);
PRINT_REG(r11, regs[4]);
PRINT_REG(r12, regs[3]);
PRINT_REG(r13, regs[2]);
PRINT_REG(r14, regs[1]);
PRINT_REG(r15, regs[0]);
#undef PRINT_REG
// Print some words near the top of the stack.
int64_t* rsp = ®s[16];
int64_t* dump_sp = rsp;
for (int col1 = 0; col1 < 8; col1++) {
tty->print("(rsp+0x%03x) 0x%016lx: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp);
os::print_location(tty, *dump_sp++);
}
for (int row = 0; row < 25; row++) {
tty->print("(rsp+0x%03x) 0x%016lx: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp);
for (int col = 0; col < 4; col++) {
tty->print(" 0x%016lx", (intptr_t)*dump_sp++);
}
tty->cr();
}
// Print some instructions around pc:
Disassembler::decode((address)pc-64, (address)pc);
tty->print_cr("--------");
Disassembler::decode((address)pc, (address)pc+32);
}
// The java_calling_convention describes stack locations as ideal slots on
// a frame with no abi restrictions. Since we must observe abi restrictions
// (like the placement of the register window) the slots must be biased by
// the following value.
static int reg2offset_in(VMReg r) {
// Account for saved rbp and return address
// This should really be in_preserve_stack_slots
return (r->reg2stack() + 4) * VMRegImpl::stack_slot_size;
}
static int reg2offset_out(VMReg r) {
return (r->reg2stack() + SharedRuntime::out_preserve_stack_slots()) * VMRegImpl::stack_slot_size;
}
// A long move
void MacroAssembler::long_move(VMRegPair src, VMRegPair dst, Register tmp, int in_stk_bias, int out_stk_bias) {
// The calling conventions assures us that each VMregpair is either
// all really one physical register or adjacent stack slots.
if (src.is_single_phys_reg() ) {
if (dst.is_single_phys_reg()) {
if (dst.first() != src.first()) {
mov(dst.first()->as_Register(), src.first()->as_Register());
}
} else {
assert(dst.is_single_reg(), "not a stack pair: (%s, %s), (%s, %s)",
src.first()->name(), src.second()->name(), dst.first()->name(), dst.second()->name());
movq(Address(rsp, reg2offset_out(dst.first()) + out_stk_bias), src.first()->as_Register());
}
} else if (dst.is_single_phys_reg()) {
assert(src.is_single_reg(), "not a stack pair");
movq(dst.first()->as_Register(), Address(rbp, reg2offset_in(src.first()) + in_stk_bias));
} else {
assert(src.is_single_reg() && dst.is_single_reg(), "not stack pairs");
movq(tmp, Address(rbp, reg2offset_in(src.first()) + in_stk_bias));
movq(Address(rsp, reg2offset_out(dst.first()) + out_stk_bias), tmp);
}
}
// A double move
void MacroAssembler::double_move(VMRegPair src, VMRegPair dst, Register tmp, int in_stk_bias, int out_stk_bias) {
// The calling conventions assures us that each VMregpair is either
// all really one physical register or adjacent stack slots.
if (src.is_single_phys_reg() ) {
if (dst.is_single_phys_reg()) {
// In theory these overlap but the ordering is such that this is likely a nop
if ( src.first() != dst.first()) {
movdbl(dst.first()->as_XMMRegister(), src.first()->as_XMMRegister());
}
} else {
assert(dst.is_single_reg(), "not a stack pair");
movdbl(Address(rsp, reg2offset_out(dst.first()) + out_stk_bias), src.first()->as_XMMRegister());
}
} else if (dst.is_single_phys_reg()) {
assert(src.is_single_reg(), "not a stack pair");
movdbl(dst.first()->as_XMMRegister(), Address(rbp, reg2offset_in(src.first()) + in_stk_bias));
} else {
assert(src.is_single_reg() && dst.is_single_reg(), "not stack pairs");
movq(tmp, Address(rbp, reg2offset_in(src.first()) + in_stk_bias));
movq(Address(rsp, reg2offset_out(dst.first()) + out_stk_bias), tmp);
}
}
// A float arg may have to do float reg int reg conversion
void MacroAssembler::float_move(VMRegPair src, VMRegPair dst, Register tmp, int in_stk_bias, int out_stk_bias) {
assert(!src.second()->is_valid() && !dst.second()->is_valid(), "bad float_move");
// The calling conventions assures us that each VMregpair is either
// all really one physical register or adjacent stack slots.
if (src.first()->is_stack()) {
if (dst.first()->is_stack()) {
movl(tmp, Address(rbp, reg2offset_in(src.first()) + in_stk_bias));
movptr(Address(rsp, reg2offset_out(dst.first()) + out_stk_bias), tmp);
} else {
// stack to reg
assert(dst.first()->is_XMMRegister(), "only expect xmm registers as parameters");
movflt(dst.first()->as_XMMRegister(), Address(rbp, reg2offset_in(src.first()) + in_stk_bias));
}
} else if (dst.first()->is_stack()) {
// reg to stack
assert(src.first()->is_XMMRegister(), "only expect xmm registers as parameters");
movflt(Address(rsp, reg2offset_out(dst.first()) + out_stk_bias), src.first()->as_XMMRegister());
} else {
// reg to reg
// In theory these overlap but the ordering is such that this is likely a nop
if ( src.first() != dst.first()) {
movdbl(dst.first()->as_XMMRegister(), src.first()->as_XMMRegister());
}
}
}
// On 64 bit we will store integer like items to the stack as
// 64 bits items (x86_32/64 abi) even though java would only store
// 32bits for a parameter. On 32bit it will simply be 32 bits
// So this routine will do 32->32 on 32bit and 32->64 on 64bit
void MacroAssembler::move32_64(VMRegPair src, VMRegPair dst, Register tmp, int in_stk_bias, int out_stk_bias) {
if (src.first()->is_stack()) {
if (dst.first()->is_stack()) {
// stack to stack
movslq(tmp, Address(rbp, reg2offset_in(src.first()) + in_stk_bias));
movq(Address(rsp, reg2offset_out(dst.first()) + out_stk_bias), tmp);
} else {
// stack to reg
movslq(dst.first()->as_Register(), Address(rbp, reg2offset_in(src.first()) + in_stk_bias));
}
} else if (dst.first()->is_stack()) {
// reg to stack
// Do we really have to sign extend???
// __ movslq(src.first()->as_Register(), src.first()->as_Register());
movq(Address(rsp, reg2offset_out(dst.first()) + out_stk_bias), src.first()->as_Register());
} else {
// Do we really have to sign extend???
// __ movslq(dst.first()->as_Register(), src.first()->as_Register());
if (dst.first() != src.first()) {
movq(dst.first()->as_Register(), src.first()->as_Register());
}
}
}
void MacroAssembler::move_ptr(VMRegPair src, VMRegPair dst) {
if (src.first()->is_stack()) {
if (dst.first()->is_stack()) {
// stack to stack
movq(rax, Address(rbp, reg2offset_in(src.first())));
movq(Address(rsp, reg2offset_out(dst.first())), rax);
} else {
// stack to reg
movq(dst.first()->as_Register(), Address(rbp, reg2offset_in(src.first())));
}
} else if (dst.first()->is_stack()) {
// reg to stack
movq(Address(rsp, reg2offset_out(dst.first())), src.first()->as_Register());
} else {
if (dst.first() != src.first()) {
movq(dst.first()->as_Register(), src.first()->as_Register());
}
}
}
// An oop arg. Must pass a handle not the oop itself
void MacroAssembler::object_move(OopMap* map,
int oop_handle_offset,
int framesize_in_slots,
VMRegPair src,
VMRegPair dst,
bool is_receiver,
int* receiver_offset) {
// must pass a handle. First figure out the location we use as a handle
Register rHandle = dst.first()->is_stack() ? rax : dst.first()->as_Register();
// See if oop is NULL if it is we need no handle
if (src.first()->is_stack()) {
// Oop is already on the stack as an argument
int offset_in_older_frame = src.first()->reg2stack() + SharedRuntime::out_preserve_stack_slots();
map->set_oop(VMRegImpl::stack2reg(offset_in_older_frame + framesize_in_slots));
if (is_receiver) {
*receiver_offset = (offset_in_older_frame + framesize_in_slots) * VMRegImpl::stack_slot_size;
}
cmpptr(Address(rbp, reg2offset_in(src.first())), NULL_WORD);
lea(rHandle, Address(rbp, reg2offset_in(src.first())));
// conditionally move a NULL
cmovptr(Assembler::equal, rHandle, Address(rbp, reg2offset_in(src.first())));
} else {
// Oop is in a register we must store it to the space we reserve
// on the stack for oop_handles and pass a handle if oop is non-NULL
const Register rOop = src.first()->as_Register();
int oop_slot;
if (rOop == j_rarg0)
oop_slot = 0;
else if (rOop == j_rarg1)
oop_slot = 1;
else if (rOop == j_rarg2)
oop_slot = 2;
else if (rOop == j_rarg3)
oop_slot = 3;
else if (rOop == j_rarg4)
oop_slot = 4;
else {
assert(rOop == j_rarg5, "wrong register");
oop_slot = 5;
}
oop_slot = oop_slot * VMRegImpl::slots_per_word + oop_handle_offset;
int offset = oop_slot*VMRegImpl::stack_slot_size;
map->set_oop(VMRegImpl::stack2reg(oop_slot));
// Store oop in handle area, may be NULL
movptr(Address(rsp, offset), rOop);
if (is_receiver) {
*receiver_offset = offset;
}
cmpptr(rOop, NULL_WORD);
lea(rHandle, Address(rsp, offset));
// conditionally move a NULL from the handle area where it was just stored
cmovptr(Assembler::equal, rHandle, Address(rsp, offset));
}
// If arg is on the stack then place it otherwise it is already in correct reg.
if (dst.first()->is_stack()) {
movptr(Address(rsp, reg2offset_out(dst.first())), rHandle);
}
}
#endif // _LP64
// Now versions that are common to 32/64 bit
void MacroAssembler::addptr(Register dst, int32_t imm32) {
LP64_ONLY(addq(dst, imm32)) NOT_LP64(addl(dst, imm32));
}
void MacroAssembler::addptr(Register dst, Register src) {
LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src));
}
void MacroAssembler::addptr(Address dst, Register src) {
LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src));
}
void MacroAssembler::addsd(XMMRegister dst, AddressLiteral src, Register rscratch) {
assert(rscratch != noreg || always_reachable(src), "missing");
if (reachable(src)) {
Assembler::addsd(dst, as_Address(src));
} else {
lea(rscratch, src);
Assembler::addsd(dst, Address(rscratch, 0));
}
}
void MacroAssembler::addss(XMMRegister dst, AddressLiteral src, Register rscratch) {
assert(rscratch != noreg || always_reachable(src), "missing");
if (reachable(src)) {
addss(dst, as_Address(src));
} else {
lea(rscratch, src);
addss(dst, Address(rscratch, 0));
}
}
void MacroAssembler::addpd(XMMRegister dst, AddressLiteral src, Register rscratch) {
assert(rscratch != noreg || always_reachable(src), "missing");
if (reachable(src)) {
Assembler::addpd(dst, as_Address(src));
} else {
lea(rscratch, src);
Assembler::addpd(dst, Address(rscratch, 0));
}
}
// See 8273459. Function for ensuring 64-byte alignment, intended for stubs only.
// Stub code is generated once and never copied.
// NMethods can't use this because they get copied and we can't force alignment > 32 bytes.
void MacroAssembler::align64() {
align(64, (unsigned long long) pc());
}
void MacroAssembler::align32() {
align(32, (unsigned long long) pc());
}
void MacroAssembler::align(int modulus) {
// 8273459: Ensure alignment is possible with current segment alignment
assert(modulus <= CodeEntryAlignment, "Alignment must be <= CodeEntryAlignment");
align(modulus, offset());
}
void MacroAssembler::align(int modulus, int target) {
if (target % modulus != 0) {
nop(modulus - (target % modulus));
}
}
void MacroAssembler::push_f(XMMRegister r) {
subptr(rsp, wordSize);
movflt(Address(rsp, 0), r);
}
void MacroAssembler::pop_f(XMMRegister r) {
movflt(r, Address(rsp, 0));
addptr(rsp, wordSize);
}
void MacroAssembler::push_d(XMMRegister r) {
subptr(rsp, 2 * wordSize);
movdbl(Address(rsp, 0), r);
}
void MacroAssembler::pop_d(XMMRegister r) {
movdbl(r, Address(rsp, 0));
addptr(rsp, 2 * Interpreter::stackElementSize);
}
void MacroAssembler::andpd(XMMRegister dst, AddressLiteral src, Register rscratch) {
// Used in sign-masking with aligned address.
assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
assert(rscratch != noreg || always_reachable(src), "missing");
if (reachable(src)) {
Assembler::andpd(dst, as_Address(src));
} else {
lea(rscratch, src);
Assembler::andpd(dst, Address(rscratch, 0));
}
}
void MacroAssembler::andps(XMMRegister dst, AddressLiteral src, Register rscratch) {
// Used in sign-masking with aligned address.
assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
assert(rscratch != noreg || always_reachable(src), "missing");
if (reachable(src)) {
Assembler::andps(dst, as_Address(src));
} else {
lea(rscratch, src);
Assembler::andps(dst, Address(rscratch, 0));
}
}
void MacroAssembler::andptr(Register dst, int32_t imm32) {
LP64_ONLY(andq(dst, imm32)) NOT_LP64(andl(dst, imm32));
}
#ifdef _LP64
void MacroAssembler::andq(Register dst, AddressLiteral src, Register rscratch) {
assert(rscratch != noreg || always_reachable(src), "missing");
if (reachable(src)) {
andq(dst, as_Address(src));
} else {
lea(rscratch, src);
andq(dst, Address(rscratch, 0));
}
}
#endif
void MacroAssembler::atomic_incl(Address counter_addr) {
lock();
incrementl(counter_addr);
}
void MacroAssembler::atomic_incl(AddressLiteral counter_addr, Register rscratch) {
assert(rscratch != noreg || always_reachable(counter_addr), "missing");
if (reachable(counter_addr)) {
atomic_incl(as_Address(counter_addr));
} else {
lea(rscratch, counter_addr);
atomic_incl(Address(rscratch, 0));
}
}
#ifdef _LP64
void MacroAssembler::atomic_incq(Address counter_addr) {
lock();
incrementq(counter_addr);
}
void MacroAssembler::atomic_incq(AddressLiteral counter_addr, Register rscratch) {
assert(rscratch != noreg || always_reachable(counter_addr), "missing");
if (reachable(counter_addr)) {
atomic_incq(as_Address(counter_addr));
} else {
lea(rscratch, counter_addr);
atomic_incq(Address(rscratch, 0));
}
}
#endif
// Writes to stack successive pages until offset reached to check for
// stack overflow + shadow pages. This clobbers tmp.
void MacroAssembler::bang_stack_size(Register size, Register tmp) {
movptr(tmp, rsp);
// Bang stack for total size given plus shadow page size.
// Bang one page at a time because large size can bang beyond yellow and
// red zones.
Label loop;
bind(loop);
movl(Address(tmp, (-os::vm_page_size())), size );
subptr(tmp, os::vm_page_size());
subl(size, os::vm_page_size());
jcc(Assembler::greater, loop);
// Bang down shadow pages too.
// At this point, (tmp-0) is the last address touched, so don't
// touch it again. (It was touched as (tmp-pagesize) but then tmp
// was post-decremented.) Skip this address by starting at i=1, and
// touch a few more pages below. N.B. It is important to touch all
// the way down including all pages in the shadow zone.
for (int i = 1; i < ((int)StackOverflow::stack_shadow_zone_size() / os::vm_page_size()); i++) {
// this could be any sized move but this is can be a debugging crumb
// so the bigger the better.
movptr(Address(tmp, (-i*os::vm_page_size())), size );
}
}
void MacroAssembler::reserved_stack_check() {
// testing if reserved zone needs to be enabled
Label no_reserved_zone_enabling;
Register thread = NOT_LP64(rsi) LP64_ONLY(r15_thread);
NOT_LP64(get_thread(rsi);)
cmpptr(rsp, Address(thread, JavaThread::reserved_stack_activation_offset()));
jcc(Assembler::below, no_reserved_zone_enabling);
call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::enable_stack_reserved_zone), thread);
jump(RuntimeAddress(StubRoutines::throw_delayed_StackOverflowError_entry()));
should_not_reach_here();
bind(no_reserved_zone_enabling);
}
void MacroAssembler::c2bool(Register x) {
// implements x == 0 ? 0 : 1
// note: must only look at least-significant byte of x
// since C-style booleans are stored in one byte
// only! (was bug)
andl(x, 0xFF);
setb(Assembler::notZero, x);
}
// Wouldn't need if AddressLiteral version had new name
void MacroAssembler::call(Label& L, relocInfo::relocType rtype) {
Assembler::call(L, rtype);
}
void MacroAssembler::call(Register entry) {
Assembler::call(entry);
}
void MacroAssembler::call(AddressLiteral entry, Register rscratch) {
assert(rscratch != noreg || always_reachable(entry), "missing");
if (reachable(entry)) {
Assembler::call_literal(entry.target(), entry.rspec());
} else {
lea(rscratch, entry);
Assembler::call(rscratch);
}
}
void MacroAssembler::ic_call(address entry, jint method_index) {
RelocationHolder rh = virtual_call_Relocation::spec(pc(), method_index);
movptr(rax, (intptr_t)Universe::non_oop_word());
call(AddressLiteral(entry, rh));
}
void MacroAssembler::emit_static_call_stub() {
// Static stub relocation also tags the Method* in the code-stream.
mov_metadata(rbx, (Metadata*) NULL); // Method is zapped till fixup time.
// This is recognized as unresolved by relocs/nativeinst/ic code.
jump(RuntimeAddress(pc()));
}
// Implementation of call_VM versions
void MacroAssembler::call_VM(Register oop_result,
address entry_point,
bool check_exceptions) {
Label C, E;
call(C, relocInfo::none);
jmp(E);
bind(C);
call_VM_helper(oop_result, entry_point, 0, check_exceptions);
ret(0);
bind(E);
}
void MacroAssembler::call_VM(Register oop_result,
address entry_point,
Register arg_1,
bool check_exceptions) {
Label C, E;
call(C, relocInfo::none);
jmp(E);
bind(C);
pass_arg1(this, arg_1);
call_VM_helper(oop_result, entry_point, 1, check_exceptions);
ret(0);
bind(E);
}
void MacroAssembler::call_VM(Register oop_result,
address entry_point,
Register arg_1,
Register arg_2,
bool check_exceptions) {
Label C, E;
call(C, relocInfo::none);
jmp(E);
bind(C);
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
pass_arg1(this, arg_1);
call_VM_helper(oop_result, entry_point, 2, check_exceptions);
ret(0);
bind(E);
}
void MacroAssembler::call_VM(Register oop_result,
address entry_point,
Register arg_1,
Register arg_2,
Register arg_3,
bool check_exceptions) {
Label C, E;
call(C, relocInfo::none);
jmp(E);
bind(C);
LP64_ONLY(assert(arg_1 != c_rarg3, "smashed arg"));
LP64_ONLY(assert(arg_2 != c_rarg3, "smashed arg"));
pass_arg3(this, arg_3);
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
pass_arg1(this, arg_1);
call_VM_helper(oop_result, entry_point, 3, check_exceptions);
ret(0);
bind(E);
}
void MacroAssembler::call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
int number_of_arguments,
bool check_exceptions) {
Register thread = LP64_ONLY(r15_thread) NOT_LP64(noreg);
call_VM_base(oop_result, thread, last_java_sp, entry_point, number_of_arguments, check_exceptions);
}
void MacroAssembler::call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
bool check_exceptions) {
pass_arg1(this, arg_1);
call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions);
}
void MacroAssembler::call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
Register arg_2,
bool check_exceptions) {
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
pass_arg1(this, arg_1);
call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions);
}
void MacroAssembler::call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
Register arg_2,
Register arg_3,
bool check_exceptions) {
LP64_ONLY(assert(arg_1 != c_rarg3, "smashed arg"));
LP64_ONLY(assert(arg_2 != c_rarg3, "smashed arg"));
pass_arg3(this, arg_3);
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
pass_arg1(this, arg_1);
call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions);
}
void MacroAssembler::super_call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
int number_of_arguments,
bool check_exceptions) {
Register thread = LP64_ONLY(r15_thread) NOT_LP64(noreg);
MacroAssembler::call_VM_base(oop_result, thread, last_java_sp, entry_point, number_of_arguments, check_exceptions);
}
void MacroAssembler::super_call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
bool check_exceptions) {
pass_arg1(this, arg_1);
super_call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions);
}
void MacroAssembler::super_call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
Register arg_2,
bool check_exceptions) {
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
pass_arg1(this, arg_1);
super_call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions);
}
void MacroAssembler::super_call_VM(Register oop_result,
Register last_java_sp,
address entry_point,
Register arg_1,
Register arg_2,
Register arg_3,
bool check_exceptions) {
LP64_ONLY(assert(arg_1 != c_rarg3, "smashed arg"));
LP64_ONLY(assert(arg_2 != c_rarg3, "smashed arg"));
pass_arg3(this, arg_3);
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
pass_arg1(this, arg_1);
super_call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions);
}
void MacroAssembler::call_VM_base(Register oop_result,
Register java_thread,
Register last_java_sp,
address entry_point,
int number_of_arguments,
bool check_exceptions) {
// determine java_thread register
if (!java_thread->is_valid()) {
#ifdef _LP64
java_thread = r15_thread;
#else
java_thread = rdi;
get_thread(java_thread);
#endif // LP64
}
// determine last_java_sp register
if (!last_java_sp->is_valid()) {
last_java_sp = rsp;
}
// debugging support
assert(number_of_arguments >= 0 , "cannot have negative number of arguments");
LP64_ONLY(assert(java_thread == r15_thread, "unexpected register"));
#ifdef ASSERT
// TraceBytecodes does not use r12 but saves it over the call, so don't verify
// r12 is the heapbase.
LP64_ONLY(if (UseCompressedOops && !TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?");)
#endif // ASSERT
assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result"an>);
assert(java_thread != last_java_sp, "cannot use the same register for java_thread & last_java_sp"span>);
// push java thread (becomes first argument of C function)
NOT_LP64(push(java_thread); number_of_arguments++);
LP64_ONLY(mov(c_rarg0, r15_thread));
// set last Java frame before call
assert(last_java_sp != rbp, "can't use ebp/rbp");
// Only interpreter should have to set fp
set_last_Java_frame(java_thread, last_java_sp, rbp, NULL, rscratch1);
// do the call, remove parameters
MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments);
// restore the thread (cannot use the pushed argument since arguments
// may be overwritten by C code generated by an optimizing compiler);
// however can use the register value directly if it is callee saved.
if (LP64_ONLY(true ||) java_thread == rdi || java_thread == rsi) {
// rdi & rsi (also r15) are callee saved -> nothing to do
#ifdef ASSERT
guarantee(java_thread != rax, "change this code");
push(rax);
{ Label L;
get_thread(rax);
cmpptr(java_thread, rax);
jcc(Assembler::equal, L);
STOP("MacroAssembler::call_VM_base: rdi not callee saved?");
bind(L);
}
pop(rax);
#endif
} else {
get_thread(java_thread);
}
// reset last Java frame
// Only interpreter should have to clear fp
reset_last_Java_frame(java_thread, true);
// C++ interp handles this in the interpreter
check_and_handle_popframe(java_thread);
check_and_handle_earlyret(java_thread);
if (check_exceptions) {
// check for pending exceptions (java_thread is set upon return)
cmpptr(Address(java_thread, Thread::pending_exception_offset()), NULL_WORD);
#ifndef _LP64
jump_cc(Assembler::notEqual,
RuntimeAddress(StubRoutines::forward_exception_entry()));
#else
// This used to conditionally jump to forward_exception however it is
// possible if we relocate that the branch will not reach. So we must jump
// around so we can always reach
Label ok;
jcc(Assembler::equal, ok);
jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
bind(ok);
#endif // LP64
}
// get oop result if there is one and reset the value in the thread
if (oop_result->is_valid()) {
get_vm_result(oop_result, java_thread);
}
}
void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
// Calculate the value for last_Java_sp
// somewhat subtle. call_VM does an intermediate call
// which places a return address on the stack just under the
// stack pointer as the user finished with it. This allows
// use to retrieve last_Java_pc from last_Java_sp[-1].
// On 32bit we then have to push additional args on the stack to accomplish
// the actual requested call. On 64bit call_VM only can use register args
// so the only extra space is the return address that call_VM created.
// This hopefully explains the calculations here.
#ifdef _LP64
// We've pushed one address, correct last_Java_sp
lea(rax, Address(rsp, wordSize));
#else
lea(rax, Address(rsp, (1 + number_of_arguments) * wordSize));
#endif // LP64
call_VM_base(oop_result, noreg, rax, entry_point, number_of_arguments, check_exceptions);
}
// Use this method when MacroAssembler version of call_VM_leaf_base() should be called from Interpreter.
void MacroAssembler::call_VM_leaf0(address entry_point) {
MacroAssembler::call_VM_leaf_base(entry_point, 0);
}
void MacroAssembler::call_VM_leaf(address entry_point, int number_of_arguments) {
call_VM_leaf_base(entry_point, number_of_arguments);
}
void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0) {
pass_arg0(this, arg_0);
call_VM_leaf(entry_point, 1);
}
void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1) {
LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
pass_arg1(this, arg_1);
pass_arg0(this, arg_0);
call_VM_leaf(entry_point, 2);
}
void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) {
LP64_ONLY(assert(arg_0 != c_rarg2, "smashed arg"));
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
pass_arg1(this, arg_1);
pass_arg0(this, arg_0);
call_VM_leaf(entry_point, 3);
}
void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3) {
LP64_ONLY(assert(arg_0 != c_rarg3, "smashed arg"));
LP64_ONLY(assert(arg_1 != c_rarg3, "smashed arg"));
LP64_ONLY(assert(arg_2 != c_rarg3, "smashed arg"));
pass_arg3(this, arg_3);
LP64_ONLY(assert(arg_0 != c_rarg2, "smashed arg"));
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
pass_arg1(this, arg_1);
pass_arg0(this, arg_0);
call_VM_leaf(entry_point, 3);
}
void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0) {
pass_arg0(this, arg_0);
MacroAssembler::call_VM_leaf_base(entry_point, 1);
}
void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1) {
LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
pass_arg1(this, arg_1);
pass_arg0(this, arg_0);
MacroAssembler::call_VM_leaf_base(entry_point, 2);
}
void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) {
LP64_ONLY(assert(arg_0 != c_rarg2, "smashed arg"));
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
pass_arg1(this, arg_1);
pass_arg0(this, arg_0);
MacroAssembler::call_VM_leaf_base(entry_point, 3);
}
void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3) {
LP64_ONLY(assert(arg_0 != c_rarg3, "smashed arg"));
LP64_ONLY(assert(arg_1 != c_rarg3, "smashed arg"));
LP64_ONLY(assert(arg_2 != c_rarg3, "smashed arg"));
pass_arg3(this, arg_3);
LP64_ONLY(assert(arg_0 != c_rarg2, "smashed arg"));
LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
pass_arg2(this, arg_2);
LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
pass_arg1(this, arg_1);
pass_arg0(this, arg_0);
MacroAssembler::call_VM_leaf_base(entry_point, 4);
}
void MacroAssembler::get_vm_result(Register oop_result, Register java_thread) {
movptr(oop_result, Address(java_thread, JavaThread::vm_result_offset()));
movptr(Address(java_thread, JavaThread::vm_result_offset()), NULL_WORD);
verify_oop_msg(oop_result, "broken oop in call_VM_base");
}
void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thread) {
movptr(metadata_result, Address(java_thread, JavaThread::vm_result_2_offset()));
movptr(Address(java_thread, JavaThread::vm_result_2_offset()), NULL_WORD);
}
void MacroAssembler::check_and_handle_earlyret(Register java_thread) {
}
void MacroAssembler::check_and_handle_popframe(Register java_thread) {
}
void MacroAssembler::cmp32(AddressLiteral src1, int32_t imm, Register rscratch) {
assert(rscratch != noreg || always_reachable(src1), "missing");
if (reachable(src1)) {
cmpl(as_Address(src1), imm);
} else {
lea(rscratch, src1);
cmpl(Address(rscratch, 0), imm);
}
}
void MacroAssembler::cmp32(Register src1, AddressLiteral src2, Register rscratch) {
assert(!src2.is_lval(), "use cmpptr");
assert(rscratch != noreg || always_reachable(src2), "missing");
if (reachable(src2)) {
cmpl(src1, as_Address(src2));
} else {
lea(rscratch, src2);
cmpl(src1, Address(rscratch, 0));
}
}
void MacroAssembler::cmp32(Register src1, int32_t imm) {
Assembler::cmpl(src1, imm);
}
void MacroAssembler::cmp32(Register src1, Address src2) {
Assembler::cmpl(src1, src2);
}
void MacroAssembler::cmpsd2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less) {
ucomisd(opr1, opr2);
Label L;
if (unordered_is_less) {
movl(dst, -1);
jcc(Assembler::parity, L);
jcc(Assembler::below , L);
movl(dst, 0);
jcc(Assembler::equal , L);
increment(dst);
} else { // unordered is greater
movl(dst, 1);
jcc(Assembler::parity, L);
jcc(Assembler::above , L);
movl(dst, 0);
jcc(Assembler::equal , L);
decrementl(dst);
}
bind(L);
}
void MacroAssembler::cmpss2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less) {
ucomiss(opr1, opr2);
Label L;
if (unordered_is_less) {
movl(dst, -1);
jcc(Assembler::parity, L);
jcc(Assembler::below , L);
movl(dst, 0);
jcc(Assembler::equal , L);
increment(dst);
} else { // unordered is greater
movl(dst, 1);
jcc(Assembler::parity, L);
jcc(Assembler::above , L);
movl(dst, 0);
jcc(Assembler::equal , L);
decrementl(dst);
}
bind(L);
}
void MacroAssembler::cmp8(AddressLiteral src1, int imm, Register rscratch) {
assert(rscratch != noreg || always_reachable(src1), "missing");
if (reachable(src1)) {
cmpb(as_Address(src1), imm);
} else {
lea(rscratch, src1);
cmpb(Address(rscratch, 0), imm);
}
}
void MacroAssembler::cmpptr(Register src1, AddressLiteral src2, Register rscratch) {
#ifdef _LP64
assert(rscratch != noreg || always_reachable(src2), "missing");
if (src2.is_lval()) {
movptr(rscratch, src2);
Assembler::cmpq(src1, rscratch);
} else if (reachable(src2)) {
cmpq(src1, as_Address(src2));
} else {
lea(rscratch, src2);
Assembler::cmpq(src1, Address(rscratch, 0));
}
#else
assert(rscratch == noreg, "not needed");
if (src2.is_lval()) {
cmp_literal32(src1, (int32_t)src2.target(), src2.rspec());
} else {
cmpl(src1, as_Address(src2));
}
#endif // _LP64
}
void MacroAssembler::cmpptr(Address src1, AddressLiteral src2, Register rscratch) {
assert(src2.is_lval(), "not a mem-mem compare");
#ifdef _LP64
// moves src2's literal address
movptr(rscratch, src2);
Assembler::cmpq(src1, rscratch);
#else
assert(rscratch == noreg, "not needed");
cmp_literal32(src1, (int32_t)src2.target(), src2.rspec());
#endif // _LP64
}
void MacroAssembler::cmpoop(Register src1, Register src2) {
cmpptr(src1, src2);
}
void MacroAssembler::cmpoop(Register src1, Address src2) {
cmpptr(src1, src2);
}
#ifdef _LP64
void MacroAssembler::cmpoop(Register src1, jobject src2, Register rscratch) {
movoop(rscratch, src2);
cmpptr(src1, rscratch);
}
#endif
void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch) {
assert(rscratch != noreg || always_reachable(adr), "missing");
if (reachable(adr)) {
lock();
cmpxchgptr(reg, as_Address(adr));
} else {
lea(rscratch, adr);
lock();
cmpxchgptr(reg, Address(rscratch, 0));
}
}
void MacroAssembler::cmpxchgptr(Register reg, Address adr) {
LP64_ONLY(cmpxchgq(reg, adr)) NOT_LP64(cmpxchgl(reg, adr));
}
void MacroAssembler::comisd(XMMRegister dst, AddressLiteral src, Register rscratch) {
assert(rscratch != noreg || always_reachable(src), "missing");
if (reachable(src)) {
Assembler::comisd(dst, as_Address(src));
} else {
lea(rscratch, src);
Assembler::comisd(dst, Address(rscratch, 0));
}
}
void MacroAssembler::comiss(XMMRegister dst, AddressLiteral src, Register rscratch) {
assert(rscratch != noreg || always_reachable(src), "missing");
if (reachable(src)) {
Assembler::comiss(dst, as_Address(src));
} else {
lea(rscratch, src);
Assembler::comiss(dst, Address(rscratch, 0));
}
}
void MacroAssembler::cond_inc32(Condition cond, AddressLiteral counter_addr, Register rscratch) {
assert(rscratch != noreg || always_reachable(counter_addr), "missing");
Condition negated_cond = negate_condition(cond);
Label L;
jcc(negated_cond, L);
pushf(); // Preserve flags
atomic_incl(counter_addr, rscratch);
popf();
bind(L);
}
int MacroAssembler::corrected_idivl(Register reg) {
// Full implementation of Java idiv and irem; checks for
// special case as described in JVM spec., p.243 & p.271.
// The function returns the (pc) offset of the idivl
// instruction - may be needed for implicit exceptions.
//
// normal case special case
//
// input : rax,: dividend min_int
// reg: divisor (may not be rax,/rdx) -1
//
// output: rax,: quotient (= rax, idiv reg) min_int
// rdx: remainder (= rax, irem reg) 0
assert(reg != rax && reg != rdx, "reg cannot be rax, or rdx register");
const int min_int = 0x80000000;
Label normal_case, special_case;
// check for special case
cmpl(rax, min_int);
jcc(Assembler::notEqual, normal_case);
xorl(rdx, rdx); // prepare rdx for possible special case (where remainder = 0)
cmpl(reg, -1);
jcc(Assembler::equal, special_case);
// handle normal case
bind(normal_case);
cdql();
int idivl_offset = offset();
idivl(reg);
// normal and special case exit
bind(special_case);
return idivl_offset;
}
void MacroAssembler::decrementl(Register reg, int value) {
if (value == min_jint) {subl(reg, value) ; return; }
if (value < 0) { incrementl(reg, -value); return; }
if (value == 0) { ; return; }
if (value == 1 && UseIncDec) { decl(reg) ; return; }
/* else */ { subl(reg, value) ; return; }
}
void MacroAssembler::decrementl(Address dst, int value) {
--> --------------------
--> maximum size reached
--> --------------------
¤ Dauer der Verarbeitung: 0.131 Sekunden
(vorverarbeitet)
¤
|
Haftungshinweis
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.
|