mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-02 04:00:16 +00:00
8210498: nmethod entry barriers
Reviewed-by: kvn, pliden
This commit is contained in:
parent
e39c5811b5
commit
0192c14c9b
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void BarrierSetNMethod::disarm(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::is_armed(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
40
src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp
Normal file
40
src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void BarrierSetNMethod::disarm(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::is_armed(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
40
src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp
Normal file
40
src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void BarrierSetNMethod::disarm(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::is_armed(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
40
src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp
Normal file
40
src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void BarrierSetNMethod::disarm(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::is_armed(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
40
src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp
Normal file
40
src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void BarrierSetNMethod::disarm(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::is_armed(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
@ -26,6 +26,8 @@
|
||||
#include "c1/c1_MacroAssembler.hpp"
|
||||
#include "c1/c1_Runtime1.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "oops/arrayOop.hpp"
|
||||
@ -330,6 +332,9 @@ void C1_MacroAssembler::build_frame(int frame_size_in_bytes, int bang_size_in_by
|
||||
}
|
||||
#endif // TIERED
|
||||
decrement(rsp, frame_size_in_bytes); // does not emit code for frame_size == 0
|
||||
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->nmethod_entry_barrier(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -23,7 +23,9 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "interpreter/interp_masm.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
@ -322,3 +324,22 @@ void BarrierSetAssembler::incr_allocated_bytes(MacroAssembler* masm, Register th
|
||||
__ adcl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())+4), 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm) {
|
||||
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
|
||||
if (bs_nm == NULL) {
|
||||
return;
|
||||
}
|
||||
#ifndef _LP64
|
||||
ShouldNotReachHere();
|
||||
#else
|
||||
Label continuation;
|
||||
Register thread = LP64_ONLY(r15_thread);
|
||||
Address disarmed_addr(thread, in_bytes(bs_nm->thread_disarmed_offset()));
|
||||
__ align(8);
|
||||
__ cmpl(disarmed_addr, 0);
|
||||
__ jcc(Assembler::equal, continuation);
|
||||
__ call(RuntimeAddress(StubRoutines::x86::method_entry_barrier()));
|
||||
__ bind(continuation);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -83,6 +83,8 @@ public:
|
||||
Label& slow_case);
|
||||
|
||||
virtual void barrier_stubs_init() {}
|
||||
|
||||
virtual void nmethod_entry_barrier(MacroAssembler* masm);
|
||||
};
|
||||
|
||||
#endif // CPU_X86_GC_SHARED_BARRIERSETASSEMBLER_X86_HPP
|
||||
|
||||
155
src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp
Normal file
155
src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 "code/codeCache.hpp"
|
||||
#include "code/nativeInst.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/sharedRuntime.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/align.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
class NativeNMethodCmpBarrier: public NativeInstruction {
|
||||
public:
|
||||
enum Intel_specific_constants {
|
||||
instruction_code = 0x81,
|
||||
instruction_size = 8,
|
||||
imm_offset = 4,
|
||||
instruction_rex_prefix = Assembler::REX | Assembler::REX_B,
|
||||
instruction_modrm = 0x7f // [r15 + offset]
|
||||
};
|
||||
|
||||
address instruction_address() const { return addr_at(0); }
|
||||
address immediate_address() const { return addr_at(imm_offset); }
|
||||
|
||||
jint get_immedate() const { return int_at(imm_offset); }
|
||||
void set_immediate(jint imm) { set_int_at(imm_offset, imm); }
|
||||
void verify() const;
|
||||
};
|
||||
|
||||
void NativeNMethodCmpBarrier::verify() const {
|
||||
if (((uintptr_t) instruction_address()) & 0x7) {
|
||||
fatal("Not properly aligned");
|
||||
}
|
||||
|
||||
int prefix = ubyte_at(0);
|
||||
if (prefix != instruction_rex_prefix) {
|
||||
tty->print_cr("Addr: " INTPTR_FORMAT " Prefix: 0x%x", p2i(instruction_address()),
|
||||
prefix);
|
||||
fatal("not a cmp barrier");
|
||||
}
|
||||
|
||||
int inst = ubyte_at(1);
|
||||
if (inst != instruction_code) {
|
||||
tty->print_cr("Addr: " INTPTR_FORMAT " Code: 0x%x", p2i(instruction_address()),
|
||||
inst);
|
||||
fatal("not a cmp barrier");
|
||||
}
|
||||
|
||||
int modrm = ubyte_at(2);
|
||||
if (modrm != instruction_modrm) {
|
||||
tty->print_cr("Addr: " INTPTR_FORMAT " mod/rm: 0x%x", p2i(instruction_address()),
|
||||
modrm);
|
||||
fatal("not a cmp barrier");
|
||||
}
|
||||
}
|
||||
|
||||
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
|
||||
/*
|
||||
* [ callers frame ]
|
||||
* [ callers return address ] <- callers rsp
|
||||
* [ callers rbp ] <- callers rbp
|
||||
* [ callers frame slots ]
|
||||
* [ return_address ] <- return_address_ptr
|
||||
* [ cookie ] <- used to write the new rsp (callers rsp)
|
||||
* [ stub rbp ]
|
||||
* [ stub stuff ]
|
||||
*/
|
||||
|
||||
address* stub_rbp = return_address_ptr - 2;
|
||||
address* callers_rsp = return_address_ptr + nm->frame_size(); /* points to callers return_address now */
|
||||
address* callers_rbp = callers_rsp - 1; // 1 to move to the callers return address, 1 more to move to the rbp
|
||||
address* cookie = return_address_ptr - 1;
|
||||
|
||||
LogTarget(Trace, nmethod, barrier) out;
|
||||
if (out.is_enabled()) {
|
||||
Thread* thread = Thread::current();
|
||||
assert(thread->is_Java_thread(), "must be JavaThread");
|
||||
JavaThread* jth = (JavaThread*) thread;
|
||||
ResourceMark mark;
|
||||
log_trace(nmethod, barrier)("deoptimize(nmethod: %p, return_addr: %p, osr: %d, thread: %p(%s), making rsp: %p) -> %p",
|
||||
nm, (address *) return_address_ptr, nm->is_osr_method(), jth,
|
||||
jth->get_thread_name(), callers_rsp, nm->verified_entry_point());
|
||||
}
|
||||
|
||||
assert(nm->frame_size() >= 3, "invariant");
|
||||
assert(*cookie == (address) -1, "invariant");
|
||||
|
||||
// Preserve caller rbp.
|
||||
*stub_rbp = *callers_rbp;
|
||||
|
||||
// At the cookie address put the callers rsp.
|
||||
*cookie = (address) callers_rsp; // should point to the return address
|
||||
|
||||
// In the slot that used to be the callers rbp we put the address that our stub needs to jump to at the end.
|
||||
// Overwriting the caller rbp should be okay since our stub rbp has the same value.
|
||||
address* jmp_addr_ptr = callers_rbp;
|
||||
*jmp_addr_ptr = SharedRuntime::get_handle_wrong_method_stub();
|
||||
}
|
||||
|
||||
// This is the offset of the entry barrier from where the frame is completed.
|
||||
// If any code changes between the end of the verified entry where the entry
|
||||
// barrier resides, and the completion of the frame, then
|
||||
// NativeNMethodCmpBarrier::verify() will immediately complain when it does
|
||||
// not find the expected native instruction at this offset, which needs updating.
|
||||
// Note that this offset is invariant of PreserveFramePointer.
|
||||
static const int entry_barrier_offset = -19;
|
||||
|
||||
static NativeNMethodCmpBarrier* native_nmethod_barrier(nmethod* nm) {
|
||||
address barrier_address = nm->code_begin() + nm->frame_complete_offset() + entry_barrier_offset;
|
||||
NativeNMethodCmpBarrier* barrier = reinterpret_cast<NativeNMethodCmpBarrier*>(barrier_address);
|
||||
debug_only(barrier->verify());
|
||||
return barrier;
|
||||
}
|
||||
|
||||
void BarrierSetNMethod::disarm(nmethod* nm) {
|
||||
if (!supports_entry_barrier(nm)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NativeNMethodCmpBarrier* cmp = native_nmethod_barrier(nm);
|
||||
cmp->set_immediate(disarmed_value());
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::is_armed(nmethod* nm) {
|
||||
if (!supports_entry_barrier(nm)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NativeNMethodCmpBarrier* cmp = native_nmethod_barrier(nm);
|
||||
return (disarmed_value() != cmp->get_immedate());
|
||||
}
|
||||
@ -5453,7 +5453,7 @@ void MacroAssembler::reinit_heapbase() {
|
||||
#endif // _LP64
|
||||
|
||||
// C2 compiled method's prolog code.
|
||||
void MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool fp_mode_24b) {
|
||||
void MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool fp_mode_24b, bool is_stub) {
|
||||
|
||||
// WARNING: Initial instruction MUST be 5 bytes or longer so that
|
||||
// NativeJump::patch_verified_entry will be able to patch out the entry
|
||||
@ -5535,6 +5535,10 @@ void MacroAssembler::verified_entry(int framesize, int stack_bang_size, bool fp_
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!is_stub) {
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->nmethod_entry_barrier(this);
|
||||
}
|
||||
}
|
||||
|
||||
// clear memory of size 'cnt' qwords, starting at 'base' using XMM/YMM registers
|
||||
|
||||
@ -1588,7 +1588,7 @@ public:
|
||||
void movl2ptr(Register dst, Register src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(if (dst != src) movl(dst, src)); }
|
||||
|
||||
// C2 compiled method's prolog code.
|
||||
void verified_entry(int framesize, int stack_bang_size, bool fp_mode_24b);
|
||||
void verified_entry(int framesize, int stack_bang_size, bool fp_mode_24b, bool is_stub);
|
||||
|
||||
// clear memory of size 'cnt' qwords, starting at 'base';
|
||||
// if 'is_large' is set, do not try to produce short loop
|
||||
|
||||
@ -2160,6 +2160,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
||||
// -2 because return address is already present and so is saved rbp
|
||||
__ subptr(rsp, stack_size - 2*wordSize);
|
||||
|
||||
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
|
||||
bs->nmethod_entry_barrier(masm);
|
||||
|
||||
// Frame is now completed as far as size and linkage.
|
||||
int frame_complete = ((intptr_t)__ pc()) - start;
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#include "ci/ciUtilities.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetAssembler.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "nativeInst_x86.hpp"
|
||||
#include "oops/instanceOop.hpp"
|
||||
@ -5194,6 +5195,83 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||
return start;
|
||||
}
|
||||
|
||||
address generate_method_entry_barrier() {
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", "nmethod_entry_barrier");
|
||||
|
||||
Label deoptimize_label;
|
||||
|
||||
address start = __ pc();
|
||||
|
||||
__ push(-1); // cookie, this is used for writing the new rsp when deoptimizing
|
||||
|
||||
BLOCK_COMMENT("Entry:");
|
||||
__ enter(); // save rbp
|
||||
|
||||
// save c_rarg0, because we want to use that value.
|
||||
// We could do without it but then we depend on the number of slots used by pusha
|
||||
__ push(c_rarg0);
|
||||
|
||||
__ lea(c_rarg0, Address(rsp, wordSize * 3)); // 1 for cookie, 1 for rbp, 1 for c_rarg0 - this should be the return address
|
||||
|
||||
__ pusha();
|
||||
|
||||
// The method may have floats as arguments, and we must spill them before calling
|
||||
// the VM runtime.
|
||||
assert(Argument::n_float_register_parameters_j == 8, "Assumption");
|
||||
const int xmm_size = wordSize * 2;
|
||||
const int xmm_spill_size = xmm_size * Argument::n_float_register_parameters_j;
|
||||
__ subptr(rsp, xmm_spill_size);
|
||||
__ movdqu(Address(rsp, xmm_size * 7), xmm7);
|
||||
__ movdqu(Address(rsp, xmm_size * 6), xmm6);
|
||||
__ movdqu(Address(rsp, xmm_size * 5), xmm5);
|
||||
__ movdqu(Address(rsp, xmm_size * 4), xmm4);
|
||||
__ movdqu(Address(rsp, xmm_size * 3), xmm3);
|
||||
__ movdqu(Address(rsp, xmm_size * 2), xmm2);
|
||||
__ movdqu(Address(rsp, xmm_size * 1), xmm1);
|
||||
__ movdqu(Address(rsp, xmm_size * 0), xmm0);
|
||||
|
||||
__ call_VM_leaf(CAST_FROM_FN_PTR(address, static_cast<int (*)(address*)>(BarrierSetNMethod::nmethod_stub_entry_barrier)), 1);
|
||||
|
||||
__ movdqu(xmm0, Address(rsp, xmm_size * 0));
|
||||
__ movdqu(xmm1, Address(rsp, xmm_size * 1));
|
||||
__ movdqu(xmm2, Address(rsp, xmm_size * 2));
|
||||
__ movdqu(xmm3, Address(rsp, xmm_size * 3));
|
||||
__ movdqu(xmm4, Address(rsp, xmm_size * 4));
|
||||
__ movdqu(xmm5, Address(rsp, xmm_size * 5));
|
||||
__ movdqu(xmm6, Address(rsp, xmm_size * 6));
|
||||
__ movdqu(xmm7, Address(rsp, xmm_size * 7));
|
||||
__ addptr(rsp, xmm_spill_size);
|
||||
|
||||
__ cmpl(rax, 1); // 1 means deoptimize
|
||||
__ jcc(Assembler::equal, deoptimize_label);
|
||||
|
||||
__ popa();
|
||||
__ pop(c_rarg0);
|
||||
|
||||
__ leave();
|
||||
|
||||
__ addptr(rsp, 1 * wordSize); // cookie
|
||||
__ ret(0);
|
||||
|
||||
|
||||
__ BIND(deoptimize_label);
|
||||
|
||||
__ popa();
|
||||
__ pop(c_rarg0);
|
||||
|
||||
__ leave();
|
||||
|
||||
// this can be taken out, but is good for verification purposes. getting a SIGSEGV
|
||||
// here while still having a correct stack is valuable
|
||||
__ testptr(rsp, Address(rsp, 0));
|
||||
|
||||
__ movptr(rsp, Address(rsp, 0)); // new rsp was written in the barrier
|
||||
__ jmp(Address(rsp, -1 * wordSize)); // jmp target should be callers verified_entry_point
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
@ -5831,6 +5909,11 @@ address generate_cipherBlockChaining_decryptVectorAESCrypt() {
|
||||
generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry,
|
||||
&StubRoutines::_safefetchN_fault_pc,
|
||||
&StubRoutines::_safefetchN_continuation_pc);
|
||||
|
||||
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
|
||||
if (bs_nm != NULL) {
|
||||
StubRoutines::x86::_method_entry_barrier = generate_method_entry_barrier();
|
||||
}
|
||||
#ifdef COMPILER2
|
||||
if (UseMultiplyToLenIntrinsic) {
|
||||
StubRoutines::_multiplyToLen = generate_multiplyToLen();
|
||||
|
||||
@ -55,8 +55,14 @@ class x86 {
|
||||
static address _double_sign_mask;
|
||||
static address _double_sign_flip;
|
||||
|
||||
static address _method_entry_barrier;
|
||||
|
||||
public:
|
||||
|
||||
static address method_entry_barrier() {
|
||||
return _method_entry_barrier;
|
||||
}
|
||||
|
||||
static address get_previous_fp_entry() {
|
||||
return _get_previous_fp_entry;
|
||||
}
|
||||
|
||||
@ -42,3 +42,4 @@ address StubRoutines::x86::_float_sign_mask = NULL;
|
||||
address StubRoutines::x86::_float_sign_flip = NULL;
|
||||
address StubRoutines::x86::_double_sign_mask = NULL;
|
||||
address StubRoutines::x86::_double_sign_flip = NULL;
|
||||
address StubRoutines::x86::_method_entry_barrier = NULL;
|
||||
|
||||
@ -890,6 +890,15 @@ void MachPrologNode::format(PhaseRegAlloc* ra_, outputStream* st) const {
|
||||
st->print("# stack alignment check");
|
||||
#endif
|
||||
}
|
||||
if (C->stub_function() != NULL && BarrierSet::barrier_set()->barrier_set_nmethod() != NULL) {
|
||||
st->print("\n\t");
|
||||
st->print("cmpl [r15_thread + #disarmed_offset], #disarmed_value\t");
|
||||
st->print("\n\t");
|
||||
st->print("je fast_entry\t");
|
||||
st->print("\n\t");
|
||||
st->print("call #nmethod_entry_barrier_stub\t");
|
||||
st->print("\n\tfast_entry:");
|
||||
}
|
||||
st->cr();
|
||||
}
|
||||
#endif
|
||||
@ -901,7 +910,7 @@ void MachPrologNode::emit(CodeBuffer &cbuf, PhaseRegAlloc *ra_) const {
|
||||
int framesize = C->frame_size_in_bytes();
|
||||
int bangsize = C->bang_size_in_bytes();
|
||||
|
||||
__ verified_entry(framesize, C->need_stack_bang(bangsize)?bangsize:0, false);
|
||||
__ verified_entry(framesize, C->need_stack_bang(bangsize)?bangsize:0, false, C->stub_function() != NULL);
|
||||
|
||||
C->set_frame_complete(cbuf.insts_size());
|
||||
|
||||
|
||||
40
src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp
Normal file
40
src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
void BarrierSetNMethod::deoptimize(nmethod* nm, address* return_address_ptr) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
void BarrierSetNMethod::disarm(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::is_armed(nmethod* nm) {
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
@ -186,6 +186,7 @@ public:
|
||||
bool contains(address addr) const { return content_begin() <= addr && addr < content_end(); }
|
||||
bool is_frame_complete_at(address addr) const { return _frame_complete_offset != CodeOffsets::frame_never_safe &&
|
||||
code_contains(addr) && addr >= code_begin() + _frame_complete_offset; }
|
||||
int frame_complete_offset() const { return _frame_complete_offset; }
|
||||
|
||||
// CodeCache support: really only used by the nmethods, but in order to get
|
||||
// asserts and certain bookkeeping to work in the CodeCache they are defined
|
||||
|
||||
@ -40,6 +40,7 @@ EpsilonBarrierSet::EpsilonBarrierSet() : BarrierSet(
|
||||
make_barrier_set_assembler<BarrierSetAssembler>(),
|
||||
make_barrier_set_c1<BarrierSetC1>(),
|
||||
make_barrier_set_c2<BarrierSetC2>(),
|
||||
NULL /* barrier_set_nmethod */,
|
||||
BarrierSet::FakeRtti(BarrierSet::EpsilonBarrierSet)) {};
|
||||
|
||||
void EpsilonBarrierSet::on_thread_create(Thread *thread) {
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
class BarrierSetAssembler;
|
||||
class BarrierSetC1;
|
||||
class BarrierSetC2;
|
||||
class BarrierSetNMethod;
|
||||
class JavaThread;
|
||||
|
||||
// This class provides the interface between a barrier implementation and
|
||||
@ -72,6 +73,7 @@ private:
|
||||
BarrierSetAssembler* _barrier_set_assembler;
|
||||
BarrierSetC1* _barrier_set_c1;
|
||||
BarrierSetC2* _barrier_set_c2;
|
||||
BarrierSetNMethod* _barrier_set_nmethod;
|
||||
|
||||
public:
|
||||
// Metafunction mapping a class derived from BarrierSet to the
|
||||
@ -95,11 +97,13 @@ protected:
|
||||
BarrierSet(BarrierSetAssembler* barrier_set_assembler,
|
||||
BarrierSetC1* barrier_set_c1,
|
||||
BarrierSetC2* barrier_set_c2,
|
||||
BarrierSetNMethod* barrier_set_nmethod,
|
||||
const FakeRtti& fake_rtti) :
|
||||
_fake_rtti(fake_rtti),
|
||||
_barrier_set_assembler(barrier_set_assembler),
|
||||
_barrier_set_c1(barrier_set_c1),
|
||||
_barrier_set_c2(barrier_set_c2) {}
|
||||
_barrier_set_c2(barrier_set_c2),
|
||||
_barrier_set_nmethod(barrier_set_nmethod) {}
|
||||
~BarrierSet() { }
|
||||
|
||||
template <class BarrierSetAssemblerT>
|
||||
@ -156,6 +160,10 @@ public:
|
||||
return _barrier_set_c2;
|
||||
}
|
||||
|
||||
BarrierSetNMethod* barrier_set_nmethod() {
|
||||
return _barrier_set_nmethod;
|
||||
}
|
||||
|
||||
// The AccessBarrier of a BarrierSet subclass is called by the Access API
|
||||
// (cf. oops/access.hpp) to perform decorated accesses. GC implementations
|
||||
// may override these default access operations by declaring an
|
||||
|
||||
87
src/hotspot/share/gc/shared/barrierSetNMethod.cpp
Normal file
87
src/hotspot/share/gc/shared/barrierSetNMethod.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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 "code/codeCache.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "gc/shared/barrierSet.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
int BarrierSetNMethod::disarmed_value() const {
|
||||
char* disarmed_addr = reinterpret_cast<char*>(Thread::current());
|
||||
disarmed_addr += in_bytes(thread_disarmed_offset());
|
||||
return *reinterpret_cast<int*>(disarmed_addr);
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::supports_entry_barrier(nmethod* nm) {
|
||||
if (nm->method()->is_method_handle_intrinsic()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!nm->is_native_method() && !nm->is_compiled_by_c2() && !nm->is_compiled_by_c1()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int BarrierSetNMethod::nmethod_stub_entry_barrier(address* return_address_ptr) {
|
||||
address return_address = *return_address_ptr;
|
||||
CodeBlob* cb = CodeCache::find_blob(return_address);
|
||||
assert(cb != NULL, "invariant");
|
||||
|
||||
nmethod* nm = cb->as_nmethod();
|
||||
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
|
||||
|
||||
if (!bs_nm->is_armed(nm)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(!nm->is_osr_method(), "Should not reach here");
|
||||
// Called upon first entry after being armed
|
||||
bool may_enter = bs_nm->nmethod_entry_barrier(nm);
|
||||
if (!may_enter) {
|
||||
log_trace(nmethod, barrier)("Deoptimizing nmethod: " PTR_FORMAT, p2i(nm));
|
||||
bs_nm->deoptimize(nm, return_address_ptr);
|
||||
}
|
||||
return may_enter ? 0 : 1;
|
||||
}
|
||||
|
||||
bool BarrierSetNMethod::nmethod_osr_entry_barrier(nmethod* nm) {
|
||||
// This check depends on the invariant that all nmethods that are deoptimized / made not entrant
|
||||
// are NOT disarmed.
|
||||
// This invariant is important because a method can be deoptimized after the method have been
|
||||
// resolved / looked up by OSR by another thread. By not deoptimizing them we guarantee that
|
||||
// a deoptimized method will always hit the barrier and come to the same conclusion - deoptimize
|
||||
if (!is_armed(nm)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
assert(nm->is_osr_method(), "Should not reach here");
|
||||
log_trace(nmethod, barrier)("Running osr nmethod entry barrier: " PTR_FORMAT, p2i(nm));
|
||||
return nmethod_entry_barrier(nm);
|
||||
}
|
||||
52
src/hotspot/share/gc/shared/barrierSetNMethod.hpp
Normal file
52
src/hotspot/share/gc/shared/barrierSetNMethod.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_CODE_NMETHOD_BARRIER_HPP
|
||||
#define SHARE_CODE_NMETHOD_BARRIER_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/sizes.hpp"
|
||||
|
||||
class nmethod;
|
||||
|
||||
class BarrierSetNMethod: public CHeapObj<mtGC> {
|
||||
bool supports_entry_barrier(nmethod* nm);
|
||||
void deoptimize(nmethod* nm, address* return_addr_ptr);
|
||||
|
||||
protected:
|
||||
virtual int disarmed_value() const;
|
||||
virtual bool nmethod_entry_barrier(nmethod* nm) = 0;
|
||||
|
||||
public:
|
||||
virtual ByteSize thread_disarmed_offset() const = 0;
|
||||
|
||||
static int nmethod_stub_entry_barrier(address* return_address_ptr);
|
||||
bool nmethod_osr_entry_barrier(nmethod* nm);
|
||||
bool is_armed(nmethod* nm);
|
||||
void disarm(nmethod* nm);
|
||||
};
|
||||
|
||||
|
||||
#endif // SHARE_CODE_NMETHOD_BARRIER_HPP
|
||||
@ -39,6 +39,7 @@ protected:
|
||||
: BarrierSet(barrier_set_assembler,
|
||||
barrier_set_c1,
|
||||
barrier_set_c2,
|
||||
NULL /* barrier_set_nmethod */,
|
||||
fake_rtti.add_tag(BarrierSet::ModRef)) { }
|
||||
~ModRefBarrierSet() { }
|
||||
|
||||
|
||||
@ -43,6 +43,7 @@ ZBarrierSet::ZBarrierSet() :
|
||||
BarrierSet(make_barrier_set_assembler<ZBarrierSetAssembler>(),
|
||||
make_barrier_set_c1<ZBarrierSetC1>(),
|
||||
make_barrier_set_c2<ZBarrierSetC2>(),
|
||||
NULL /* barrier_set_nmethod */,
|
||||
BarrierSet::FakeRtti(BarrierSet::ZBarrierSet)) {}
|
||||
|
||||
ZBarrierSetAssembler* ZBarrierSet::assembler() {
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "code/codeCache.hpp"
|
||||
#include "compiler/compileBroker.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "gc/shared/barrierSetNMethod.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "interpreter/interpreter.hpp"
|
||||
#include "interpreter/interpreterRuntime.hpp"
|
||||
@ -1045,6 +1046,13 @@ nmethod* InterpreterRuntime::frequency_counter_overflow(JavaThread* thread, addr
|
||||
Method* method = last_frame.method();
|
||||
int bci = method->bci_from(last_frame.bcp());
|
||||
nm = method->lookup_osr_nmethod_for(bci, CompLevel_none, false);
|
||||
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
|
||||
if (nm != NULL && bs_nm != NULL) {
|
||||
// in case the transition passed a safepoint we need to barrier this again
|
||||
if (!bs_nm->nmethod_osr_entry_barrier(nm)) {
|
||||
nm = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nm != NULL && thread->is_interp_only_mode()) {
|
||||
// Normally we never get an nm if is_interp_only_mode() is true, because
|
||||
@ -1081,6 +1089,13 @@ IRT_ENTRY(nmethod*,
|
||||
nmethod* osr_nm = CompilationPolicy::policy()->event(method, method, branch_bci, bci, CompLevel_none, NULL, thread);
|
||||
assert(!HAS_PENDING_EXCEPTION, "Event handler should not throw any exceptions");
|
||||
|
||||
BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod();
|
||||
if (osr_nm != NULL && bs_nm != NULL) {
|
||||
if (!bs_nm->nmethod_osr_entry_barrier(osr_nm)) {
|
||||
osr_nm = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (osr_nm != NULL) {
|
||||
// We may need to do on-stack replacement which requires that no
|
||||
// monitors in the activation are biased because their
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user