8210498: nmethod entry barriers

Reviewed-by: kvn, pliden
This commit is contained in:
Erik Österlund 2018-10-16 13:18:22 +02:00
parent e39c5811b5
commit 0192c14c9b
25 changed files with 699 additions and 4 deletions

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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

View 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());
}

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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();

View File

@ -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;
}

View File

@ -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;

View File

@ -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());

View 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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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

View 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);
}

View 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

View File

@ -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() { }

View File

@ -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() {

View File

@ -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