--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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;
+}
--- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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 @@
}
#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);
}
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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 @@
__ 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
+}
--- a/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp Tue Oct 16 13:18:22 2018 +0200
@@ -83,6 +83,8 @@
Label& slow_case);
virtual void barrier_stubs_init() {}
+
+ virtual void nmethod_entry_barrier(MacroAssembler* masm);
};
#endif // CPU_X86_GC_SHARED_BARRIERSETASSEMBLER_X86_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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());
+}
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -5453,7 +5453,7 @@
#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 @@
}
#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
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp Tue Oct 16 13:18:22 2018 +0200
@@ -1588,7 +1588,7 @@
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
--- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -2160,6 +2160,9 @@
// -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;
--- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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 @@
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 @@
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();
--- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp Tue Oct 16 13:18:22 2018 +0200
@@ -55,8 +55,14 @@
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;
}
--- a/src/hotspot/cpu/x86/stubRoutines_x86_64.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/stubRoutines_x86_64.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -42,3 +42,4 @@
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;
--- a/src/hotspot/cpu/x86/x86_64.ad Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/cpu/x86/x86_64.ad Tue Oct 16 13:18:22 2018 +0200
@@ -890,6 +890,15 @@
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 @@
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());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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;
+}
--- a/src/hotspot/share/code/codeBlob.hpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/share/code/codeBlob.hpp Tue Oct 16 13:18:22 2018 +0200
@@ -186,6 +186,7 @@
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
--- a/src/hotspot/share/gc/epsilon/epsilonBarrierSet.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/share/gc/epsilon/epsilonBarrierSet.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -40,6 +40,7 @@
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) {
--- a/src/hotspot/share/gc/shared/barrierSet.hpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/share/gc/shared/barrierSet.hpp Tue Oct 16 13:18:22 2018 +0200
@@ -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 @@
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 @@
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 @@
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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/barrierSetNMethod.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/shared/barrierSetNMethod.hpp Tue Oct 16 13:18:22 2018 +0200
@@ -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
--- a/src/hotspot/share/gc/shared/modRefBarrierSet.hpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/share/gc/shared/modRefBarrierSet.hpp Tue Oct 16 13:18:22 2018 +0200
@@ -39,6 +39,7 @@
: BarrierSet(barrier_set_assembler,
barrier_set_c1,
barrier_set_c2,
+ NULL /* barrier_set_nmethod */,
fake_rtti.add_tag(BarrierSet::ModRef)) { }
~ModRefBarrierSet() { }
--- a/src/hotspot/share/gc/z/zBarrierSet.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/share/gc/z/zBarrierSet.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -43,6 +43,7 @@
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() {
--- a/src/hotspot/share/interpreter/interpreterRuntime.cpp Tue Oct 16 13:16:11 2018 +0200
+++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp Tue Oct 16 13:18:22 2018 +0200
@@ -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 @@
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 @@
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