changeset 52142:ca0c25e01c5b

8210498: nmethod entry barriers Reviewed-by: kvn, pliden
author eosterlund
date Tue, 16 Oct 2018 13:18:22 +0200
parents de6dc206a92b
children ad6384355aa3
files src/hotspot/cpu/aarch64/gc/shared/barrierSetNMethod_aarch64.cpp src/hotspot/cpu/arm/gc/shared/barrierSetNMethod_arm.cpp src/hotspot/cpu/ppc/gc/shared/barrierSetNMethod_ppc.cpp src/hotspot/cpu/s390/gc/shared/barrierSetNMethod_s390.cpp src/hotspot/cpu/sparc/gc/shared/barrierSetNMethod_sparc.cpp src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.cpp src/hotspot/cpu/x86/gc/shared/barrierSetAssembler_x86.hpp src/hotspot/cpu/x86/gc/shared/barrierSetNMethod_x86.cpp src/hotspot/cpu/x86/macroAssembler_x86.cpp src/hotspot/cpu/x86/macroAssembler_x86.hpp src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp src/hotspot/cpu/x86/stubGenerator_x86_64.cpp src/hotspot/cpu/x86/stubRoutines_x86.hpp src/hotspot/cpu/x86/stubRoutines_x86_64.cpp src/hotspot/cpu/x86/x86_64.ad src/hotspot/cpu/zero/gc/shared/barrierSetNMethod_zero.cpp src/hotspot/share/code/codeBlob.hpp src/hotspot/share/gc/epsilon/epsilonBarrierSet.cpp src/hotspot/share/gc/shared/barrierSet.hpp src/hotspot/share/gc/shared/barrierSetNMethod.cpp src/hotspot/share/gc/shared/barrierSetNMethod.hpp src/hotspot/share/gc/shared/modRefBarrierSet.hpp src/hotspot/share/gc/z/zBarrierSet.cpp src/hotspot/share/interpreter/interpreterRuntime.cpp
diffstat 25 files changed, 699 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- /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