changeset 55389:b301822b42fd processorid

LongAdderCPU demo of Linux rseq
author dlong
date Wed, 22 May 2019 22:06:28 -0400
parents df063b0c6b16
children 7e07b78cbf78
files make/RunTests.gmk make/test/BuildMicrobenchmark.gmk src/hotspot/cpu/x86/assembler_x86.cpp src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp src/hotspot/cpu/x86/macroAssembler_x86.cpp src/hotspot/cpu/x86/macroAssembler_x86.hpp src/hotspot/cpu/x86/x86.ad src/hotspot/cpu/x86/x86_64.ad src/hotspot/os/linux/os_linux.cpp src/hotspot/os/linux/os_linux.hpp src/hotspot/os/linux/os_linux.inline.hpp src/hotspot/os/linux/os_types_linux.hpp src/hotspot/os/linux/rseq_linux.hpp src/hotspot/os/linux/thread_linux.cpp src/hotspot/os/linux/thread_linux.hpp src/hotspot/os/linux/thread_types_linux.hpp src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.hpp src/hotspot/os_cpu/linux_arm/thread_linux_arm.hpp src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.hpp src/hotspot/os_cpu/linux_s390/thread_linux_s390.hpp src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp src/hotspot/os_cpu/linux_x86/linux_x86.ad src/hotspot/os_cpu/linux_x86/os_linux_x86.hpp src/hotspot/os_cpu/linux_x86/os_linux_x86.inline.hpp src/hotspot/os_cpu/linux_x86/thread_linux_x86.hpp src/hotspot/os_cpu/linux_zero/thread_linux_zero.hpp src/hotspot/share/adlc/formssel.cpp src/hotspot/share/c1/c1_Compiler.cpp src/hotspot/share/c1/c1_LIR.cpp src/hotspot/share/c1/c1_LIR.hpp src/hotspot/share/c1/c1_LIRAssembler.cpp src/hotspot/share/c1/c1_LIRAssembler.hpp src/hotspot/share/c1/c1_LIRGenerator.cpp src/hotspot/share/c1/c1_LIRGenerator.hpp src/hotspot/share/c1/c1_MacroAssembler.hpp src/hotspot/share/classfile/vmSymbols.hpp src/hotspot/share/code/relocInfo.cpp src/hotspot/share/gc/shared/c2/barrierSetC2.cpp src/hotspot/share/gc/shared/c2/barrierSetC2.hpp src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.cpp src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.hpp src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp src/hotspot/share/opto/c2compiler.cpp src/hotspot/share/opto/classes.hpp src/hotspot/share/opto/compile.cpp src/hotspot/share/opto/graphKit.cpp src/hotspot/share/opto/graphKit.hpp src/hotspot/share/opto/intrinsicnode.hpp src/hotspot/share/opto/library_call.cpp src/hotspot/share/opto/matcher.cpp src/hotspot/share/opto/memnode.cpp src/hotspot/share/opto/memnode.hpp src/hotspot/share/prims/unsafe.cpp src/hotspot/share/runtime/os.hpp src/hotspot/share/runtime/thread.cpp src/hotspot/share/runtime/thread.hpp src/java.base/share/classes/java/util/concurrent/atomic/LongAdderCPU.java src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java src/java.base/share/classes/jdk/internal/misc/Unsafe.java test/jdk/java/util/concurrent/atomic/LongAdderDemo.java test/micro/org/openjdk/bench/java/util/concurrent/LongAdderAdd.java
diffstat 65 files changed, 1269 insertions(+), 68 deletions(-) [+]
line wrap: on
line diff
--- a/make/RunTests.gmk	Mon Feb 25 18:27:59 2019 +0000
+++ b/make/RunTests.gmk	Wed May 22 22:06:28 2019 -0400
@@ -668,6 +668,9 @@
 
   # Current tests needs to open java.io
   $1_MICRO_JAVA_OPTIONS += --add-opens=java.base/java.io=ALL-UNNAMED
+  # Some tests need jdk.internal.misc
+  $1_MICRO_JAVA_OPTIONS += --add-exports java.base/jdk.internal.misc=ALL-UNNAMED
+
   # Set library path for native dependencies
   $1_MICRO_JAVA_OPTIONS += -Djava.library.path=$$(TEST_IMAGE_DIR)/micro/native
 
--- a/make/test/BuildMicrobenchmark.gmk	Mon Feb 25 18:27:59 2019 +0000
+++ b/make/test/BuildMicrobenchmark.gmk	Wed May 22 22:06:28 2019 -0400
@@ -77,7 +77,9 @@
     JVM := $(JAVA) --add-modules jdk.unsupported --limit-modules java.management, \
     JAVAC := $(NEW_JAVAC), \
     DISABLE_SJAVAC := true, \
-    FLAGS := --upgrade-module-path $(JDK_OUTPUTDIR)/modules --system none $(DISABLE_WARNINGS), \
+    FLAGS := --upgrade-module-path $(JDK_OUTPUTDIR)/modules \
+        --system none $(DISABLE_WARNINGS) \
+        --add-exports java.base/jdk.internal.misc=ALL-UNNAMED, \
     SERVER_DIR := $(SJAVAC_SERVER_DIR), \
     SERVER_JVM := $(SJAVAC_SERVER_JAVA), \
 ))
--- a/src/hotspot/cpu/x86/assembler_x86.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -7955,6 +7955,13 @@
     return false;
   }
 
+  // Branches between sections might use relocInfo::runtime_call_type
+  if (adr.reloc() == relocInfo::runtime_call_type) {
+    if (code()->contains(adr._target)) {
+      return true;
+    }
+  }
+
   // Stress the correction code
   if (ForceUnreachable) {
     // Must be runtimecall reloc, see if it is in the codecache
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -1953,6 +1953,18 @@
     __ lock();
     __ cmpxchgq(newval, Address(addr, 0));
 #endif // _LP64
+  } else if (op->code() == lir_cas_long_cpu) {
+    Register cpu = op->cpu()->as_register();
+    Register offset = op->offset()->as_register_lo();
+    Register obj = (op->addr()->is_single_cpu() ? op->addr()->as_register() : op->addr()->as_register_lo());
+    Register newval = op->new_value()->as_register_lo();
+    Register oldval = op->cmp_value()->as_register_lo();
+    Register result = op->result()->as_register();
+    assert(newval != NULL, "new val must be register");
+    assert(oldval != newval, "cmp and new values must be in different registers");
+    assert(oldval != obj, "cmp and addr must be in different registers");
+    assert(newval != obj, "new value and addr must be in different registers");
+  __ compareAndSetLCPU(result, obj, offset, cpu, oldval, newval);
   } else {
     Unimplemented();
   }
@@ -4015,18 +4027,14 @@
 }
 
 void LIR_Assembler::getprocessorid(LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2) {
-  if (VM_Version::supports_rdpid()) {
-    __ rdpid(result->as_register());
-    __ andl(result->as_register(), 0xFFF); // TODO linux specific
-  } else if (VM_Version::supports_rdtscp()) {
-    assert(result->as_register() == rcx, "result register must be rcx");
-    assert(tmp1->as_register() == rdx, "tmp1 register must be rdx");
-    assert(tmp2->as_register() == rax, "tmp2 register must be rax");
-    __ rdtscp();
-    __ andl(result->as_register(), 0xFFF); // TODO linux specific
-  } else {
-    assert(false, "");
-  }
+  __ getprocessorid(result->as_register(), tmp1->as_register(), tmp2->as_register());
 }
 
+void LIR_Assembler::compareAndSetLCPU(LIR_Opr result, LIR_Opr obj, LIR_Opr offset,
+  LIR_Opr cpu, LIR_Opr oldval, LIR_Opr newval)
+{
+  __ compareAndSetLCPU(result->as_register(), obj->as_register(), offset->as_register(), cpu->as_register(), oldval->as_register(), newval->as_register());
+}
+
+
 #undef __
--- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, 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
@@ -1531,3 +1531,26 @@
   }
 }
 
+void LIRGenerator::do_compareAndSetLCPU(Intrinsic* x) {
+  LIR_Opr result = rlock_result(x);
+
+  LIRItem u(x->argument_at(0), this); // Object
+  LIRItem obj(x->argument_at(1), this); // Object
+  LIRItem offset(x->argument_at(2), this); // long
+  LIRItem cpu(x->argument_at(3), this); // int
+  LIRItem oldval(x->argument_at(4), this); // long
+  LIRItem newval(x->argument_at(5), this); // long
+
+  oldval.load_item_force(FrameMap::long0_opr);
+  newval.load_item_force(FrameMap::long1_opr);
+
+  obj.load_item();
+  offset.load_item();
+  cpu.load_item();
+  oldval.load_item();
+  newval.load_item();
+
+  __ cas_long_cpu(obj.result(), offset.result(), oldval.result(), newval.result(), LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr, cpu.result(), result);
+
+}
+
--- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -399,3 +399,11 @@
 }
 
 #endif // ifndef PRODUCT
+
+bool C1_MacroAssembler::supports_cmp_set_cpu() {
+#if defined(_LP64) && defined(LINUX) && defined(__NR_rseq)
+  return true;
+#else
+  return false;
+#endif
+}
--- a/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/c1_MacroAssembler_x86.hpp	Wed May 22 22:06:28 2019 -0400
@@ -127,4 +127,8 @@
   void restore_live_registers_except_rax(bool restore_fpu_registers);
   void restore_live_registers(bool restore_fpu_registers);
 
+#define C1_GET_PROCESSOR_ID
+#define C1_CMP_SET_CPU
+  static bool supports_cmp_set_cpu();
+
 #endif // CPU_X86_C1_MACROASSEMBLER_X86_HPP
--- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -9771,3 +9771,109 @@
 }
 
 #endif
+
+void MacroAssembler::getprocessorid(Register dst, Register tmp1, Register tmp2) {
+  if (VM_Version::supports_rdpid()) {
+    rdpid(dst);
+    andl(dst, 0xFFF); // TODO linux specific
+#ifdef LINUX
+  } else if (os::Linux::supports_rseq()) {
+    rseq_cpuid(dst);
+#endif
+  } else if (VM_Version::supports_rdtscp()) {
+    assert(dst == rcx, "result register must be rcx");
+    assert(tmp1 == rdx, "tmp1 register must be rdx");
+    assert(tmp2 == rax, "tmp2 register must be rax");
+    rdtscp();
+    andl(dst, 0xFFF); // TODO linux specific
+  } else {
+    assert(false, "");
+  }
+}
+
+void MacroAssembler::rseq_cpuid(Register dst) {
+#if defined(_LP64) && defined(LINUX) && defined(__NR_rseq)
+  assert(os::Linux::supports_rseq(), "!");
+  movl(dst, Address(r15_thread, JavaThread::rseq_cpuid_start_offset()));
+#else
+  fatal("No OS support for rseq");
+#endif
+}
+
+void MacroAssembler::compareAndSetLCPU(Register result, Address mem, Register cpu,
+    Register oldval, Register newval, Register tmp)
+{
+#if defined(_LP64) && defined(LINUX) && defined(__NR_rseq)
+    // oldval and newval can be the same
+    assert_different_registers(mem.base(), mem.index(), cpu, oldval, tmp);
+    assert_different_registers(mem.base(), mem.index(), cpu, newval, tmp);
+
+    // Reserve space for rseq_cs table
+    CodeSection* cs = code_section();
+    address rseq_cs = start_a_const(32, 32);
+    end_a_const(cs);
+
+    Label fail;
+    Label done;
+
+    address fail_block = start_a_stub(16);
+    align(4);
+    emit_int32(0x7ff7effe);
+    address fail_pc = pc();
+    end_a_stub();
+
+    lea(tmp, InternalAddress(rseq_cs));
+    movptr(Address(r15_thread, JavaThread::rseq_cs_offset()), tmp);
+
+    address start_ip = pc();
+    cmpl(cpu, Address(r15_thread, JavaThread::rseq_cpuid_offset()));
+    AddressLiteral fail_loc(fail_pc, runtime_call_Relocation::spec());
+    jump_cc(Assembler::notEqual, fail_loc);
+    cmpq(mem, oldval);
+    jump_cc(Assembler::notEqual, fail_loc);
+    movq(mem, newval);
+    address post_commit = pc();
+    
+    movl(result, 1);
+    address done_pc = pc();
+    bind(done);
+
+    // continue fail/abort block
+    address f = start_a_stub(fail_pc - fail_block);
+    assert(f == fail_pc, "fail_pc address changed");
+    address abort_ip = pc();
+    movl(result, 0);
+    AddressLiteral done_loc(done_pc, runtime_call_Relocation::spec());
+    jump(done_loc);
+    end_a_stub();
+
+    // Fill in rseq_cs table
+    address p = start_a_const(32, 32);
+    assert(p == rseq_cs, "rseq_cs address changed");
+
+    emit_int32(0);
+    emit_int32(0);
+    relocate(internal_word_Relocation::spec(start_ip));
+    emit_address(start_ip);
+    emit_int64(post_commit - start_ip);
+    relocate(internal_word_Relocation::spec(abort_ip));
+    emit_address(abort_ip);
+    end_a_const(cs);
+
+    // Need volatile barrier here?
+#else
+  fatal("No OS support for rseq");
+#endif
+}
+
+void MacroAssembler::compareAndSetLCPU(Register result, Register obj,
+    Register offset, Register cpu,
+    Register oldval, Register newval)
+{
+#if defined(_LP64) && defined(LINUX) && defined(__NR_rseq)
+    Address mem(obj, offset);
+    compareAndSetLCPU(result, mem, cpu, oldval, newval, result);
+#else
+  fatal("No OS support for rseq");
+#endif
+}
--- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp	Wed May 22 22:06:28 2019 -0400
@@ -1759,6 +1759,15 @@
   void byte_array_inflate(Register src, Register dst, Register len,
                           XMMRegister tmp1, Register tmp2);
 
+  void getprocessorid(Register dst, Register tmp1, Register tmp2);
+
+  void rseq_cpuid(Register dst);
+  void compareAndSetLCPU(Register result, Register obj, Register offset, Register cpu,
+		         Register oldval, Register newval);
+  void compareAndSetLCPU(Register result, Address mem, Register cpu,
+                         Register oldval, Register newval,
+                         Register tmp);
+
 };
 
 /**
--- a/src/hotspot/cpu/x86/x86.ad	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/x86.ad	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 //
-// Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
+// Copyright (c) 2011, 2019, 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
@@ -1450,6 +1450,11 @@
       if (UseSSE < 2)
         ret_value = false;
       break;
+    case Op_CompareAndSwapLCPU:
+      if (!os::supports_rseq()) {
+        ret_value = false;
+      }
+      break;
   }
 
   return ret_value;  // Per default match rules are supported.
--- a/src/hotspot/cpu/x86/x86_64.ad	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/cpu/x86/x86_64.ad	Wed May 22 22:06:28 2019 -0400
@@ -11285,7 +11285,7 @@
 %}
 
 instruct rdtscpProcessorId(rcx_RegI dst, rdx_RegI tmp, rax_RegI tmp1, rFlagsReg cr) %{
-  predicate(VM_Version::supports_rdtscp());
+  predicate(VM_Version::supports_rdtscp() LINUX_ONLY(&& !os::Linux::supports_rseq()));
   match(Set dst (GetProcessorId));
   effect(DEF dst, TEMP tmp, TEMP tmp1, KILL cr);
   ins_cost(100);
--- a/src/hotspot/os/linux/os_linux.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os/linux/os_linux.cpp	Wed May 22 22:06:28 2019 -0400
@@ -107,6 +107,9 @@
 # include <stdint.h>
 # include <inttypes.h>
 # include <sys/ioctl.h>
+#ifdef __NR_rseq
+# include <linux/rseq.h>
+#endif
 
 #ifndef _GNU_SOURCE
   #define _GNU_SOURCE
@@ -148,6 +151,7 @@
 pthread_t os::Linux::_main_thread;
 int os::Linux::_page_size = -1;
 bool os::Linux::_supports_fast_thread_cpu_time = false;
+bool os::Linux::_supports_rseq = false;
 uint32_t os::Linux::_os_version = 0;
 const char * os::Linux::_glibc_version = NULL;
 const char * os::Linux::_libpthread_version = NULL;
@@ -708,6 +712,10 @@
 
   assert(osthread->pthread_id() != 0, "pthread_id was not set as expected");
 
+  if (thread->is_Java_thread()) {
+    ((JavaThread*)thread)->pd_initialize_self();
+  }
+
   // call one more level start routine
   thread->call_run();
 
@@ -879,6 +887,8 @@
   // and save the caller's signal mask
   os::Linux::hotspot_sigmask(thread);
 
+  thread->pd_initialize_self();
+
   log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ", pthread id: " UINTX_FORMAT ").",
     os::current_thread_id(), (uintx) pthread_self());
 
@@ -5137,6 +5147,18 @@
   }
 #endif
 
+#ifdef __NR_rseq
+  Linux::_supports_rseq = false;
+  int r = syscall(__NR_rseq, NULL, 0, 0, 0);
+  guarantee(r == -1, "error expected, got %d", r);
+  int e = errno;
+  if (e == EINVAL) {
+    Linux::_supports_rseq = true;
+  } else {
+    guarantee(e == ENOSYS, "expected ENOSYS, got %d", e);
+  }
+#endif
+
   return JNI_OK;
 }
 
--- a/src/hotspot/os/linux/os_linux.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os/linux/os_linux.hpp	Wed May 22 22:06:28 2019 -0400
@@ -25,6 +25,8 @@
 #ifndef OS_LINUX_OS_LINUX_HPP
 #define OS_LINUX_OS_LINUX_HPP
 
+#include "os_posix.hpp"
+
 // Linux_OS defines the interface to Linux operating systems
 
 // Information about the protection of the page at address '0' on this os.
@@ -393,6 +395,11 @@
       return false;
     }
   }
+
+ private:
+  static bool _supports_rseq;
+ public:
+  static bool supports_rseq() { return _supports_rseq; }
 };
 
 #endif // OS_LINUX_OS_LINUX_HPP
--- a/src/hotspot/os/linux/os_linux.inline.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os/linux/os_linux.inline.hpp	Wed May 22 22:06:28 2019 -0400
@@ -28,6 +28,8 @@
 #include "runtime/os.hpp"
 #include "os_posix.inline.hpp"
 
+#include OS_CPU_HEADER_INLINE(os)
+
 // System includes
 
 #include <unistd.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/linux/os_types_linux.hpp	Wed May 22 22:06:28 2019 -0400
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019, 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 OS_LINUX_OS_TYPES_LINUX_HPP
+#define OS_LINUX_OS_TYPES_LINUX_HPP
+
+#include "rseq_linux.hpp"
+
+#endif // OS_LINUX_OS_TYPES_LINUX_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/linux/rseq_linux.hpp	Wed May 22 22:06:28 2019 -0400
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2019, 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 OS_LINUX_RSEQ_LINUX_HPP
+#define OS_LINUX_RSEQ_LINUX_HPP
+
+#include <sys/syscall.h>
+#ifdef __NR_rseq
+#include <linux/rseq.h>
+// Fix incorrect NULL picked up from gcc7.3 devkit linux/stddef.h
+#undef NULL
+#define __need_NULL
+#include <stddef.h>
+#endif
+
+#endif // OS_LINUX_RSEQ_LINUX_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/linux/thread_linux.cpp	Wed May 22 22:06:28 2019 -0400
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019, 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 "runtime/thread.hpp"
+
+#include <sys/syscall.h>
+#ifdef __NR_rseq
+#include <linux/rseq.h>
+#endif
+
+#define RSEQ_SIG 0x7ff7effe
+
+void JavaThread::pd_initialize_self() {
+  assert(current() == this, "must be called on current thread");
+#if defined(__NR_rseq)
+  if (os::Linux::supports_rseq()) {
+    // rseq
+    int flags = 0;
+    uint32_t sig = RSEQ_SIG;
+    rs.cpu_id = RSEQ_CPU_ID_UNINITIALIZED;
+    int r;
+    int e;
+    struct rseq *rsp = &rs;
+    r = syscall(__NR_rseq, rsp, sizeof rs, flags, sig);
+    e = errno;
+    assert(r == 0 || errno == EBUSY, "rseq register failed");
+  }
+#else
+  assert(!os::Linux::supports_rseq(), "that does not compute!");
+#endif
+}
+
+void JavaThread::pd_destroy_self() {
+  assert(current() == this, "must be called on current thread");
+#if defined(__NR_rseq)
+  if (os::Linux::supports_rseq()) {
+    // rseq
+    int flags = RSEQ_FLAG_UNREGISTER;
+    uint32_t sig = RSEQ_SIG;
+    int r;
+    int e;
+    struct rseq *rsp = &rs;
+    r = syscall(__NR_rseq, rsp, sizeof rs, flags, sig);
+    e = errno;
+    assert(r == 0 || errno == EBUSY, "rseq unregister failed");
+    rs.cpu_id = RSEQ_CPU_ID_UNINITIALIZED;
+  }
+#else
+  assert(!os::Linux::supports_rseq(), "that does not compute!");
+#endif
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/linux/thread_linux.hpp	Wed May 22 22:06:28 2019 -0400
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, 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 OS_LINUX_THREAD_LINUX_HPP
+#define OS_LINUX_THREAD_LINUX_HPP
+
+ private:
+#ifdef __NR_rseq
+  friend class os;
+  struct rseq rs;
+#endif
+ public:
+#ifdef __NR_rseq
+  static ByteSize rseq_cpuid_offset() {
+    return byte_offset_of(JavaThread, rs.cpu_id);
+  }
+  static ByteSize rseq_cpuid_start_offset() {
+    return byte_offset_of(JavaThread, rs.cpu_id_start);
+  }
+  static ByteSize rseq_cs_offset() {
+    return byte_offset_of(JavaThread, rs.rseq_cs);
+  }
+#endif
+  void pd_initialize_self();
+#define PD_DESTROY_SELF
+  void pd_destroy_self();
+
+  void pd_linux_initialize() {
+#ifdef __NR_rseq
+    memset(&rs, 0, sizeof rs);
+#endif
+  }
+
+#endif // OS_LINUX_THREAD_LINUX_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os/linux/thread_types_linux.hpp	Wed May 22 22:06:28 2019 -0400
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2019, 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 OS_LINUX_THREAD_TYPES_LINUX_HPP
+#define OS_LINUX_THREAD_TYPES_LINUX_HPP
+
+#include "rseq_linux.hpp"
+
+#endif // OS_LINUX_THREAD_TYPES_LINUX_HPP
--- a/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.hpp	Wed May 22 22:06:28 2019 -0400
@@ -26,6 +26,8 @@
 #ifndef OS_CPU_LINUX_AARCH64_THREAD_LINUX_AARCH64_HPP
 #define OS_CPU_LINUX_AARCH64_THREAD_LINUX_AARCH64_HPP
 
+#include "thread_linux.hpp"
+
  private:
 #ifdef ASSERT
   // spill stack holds N callee-save registers at each Java call and
@@ -38,6 +40,7 @@
 #endif // ASSERT
 
   void pd_initialize() {
+    pd_linux_initialize();
     _anchor.clear();
   }
 
--- a/src/hotspot/os_cpu/linux_arm/thread_linux_arm.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_arm/thread_linux_arm.hpp	Wed May 22 22:06:28 2019 -0400
@@ -25,6 +25,8 @@
 #ifndef OS_CPU_LINUX_ARM_THREAD_LINUX_ARM_HPP
 #define OS_CPU_LINUX_ARM_THREAD_LINUX_ARM_HPP
 
+#include "thread_linux.hpp"
+
  private:
   // The following thread-local variables replicate corresponding global variables.
   // They are used for a quick access from compiled code via Rthread register.
@@ -33,6 +35,7 @@
   address _card_table_base;
 
   void pd_initialize() {
+    pd_linux_initialize();
     _anchor.clear();
     _in_top_frame_unsafe_section = NULL;
   }
--- a/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.hpp	Wed May 22 22:06:28 2019 -0400
@@ -26,9 +26,12 @@
 #ifndef OS_CPU_LINUX_PPC_THREAD_LINUX_PPC_HPP
 #define OS_CPU_LINUX_PPC_THREAD_LINUX_PPC_HPP
 
+#include "thread_linux.hpp"
+
  private:
 
   void pd_initialize() {
+    pd_linux_initialize();
     _anchor.clear();
   }
 
--- a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.hpp	Wed May 22 22:06:28 2019 -0400
@@ -26,9 +26,12 @@
 #ifndef OS_CPU_LINUX_S390_THREAD_LINUX_S390_HPP
 #define OS_CPU_LINUX_S390_THREAD_LINUX_S390_HPP
 
+#include "thread_linux.hpp"
+
  private:
 
   void pd_initialize() {
+    pd_linux_initialize();
     _anchor.clear();
   }
 
--- a/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_sparc/thread_linux_sparc.hpp	Wed May 22 22:06:28 2019 -0400
@@ -25,9 +25,12 @@
 #ifndef OS_CPU_LINUX_SPARC_THREAD_LINUX_SPARC_HPP
 #define OS_CPU_LINUX_SPARC_THREAD_LINUX_SPARC_HPP
 
+#include "thread_linux.hpp"
+
 private:
 
   void pd_initialize() {
+    pd_linux_initialize();
     _anchor.clear();
     _base_of_stack_pointer        = NULL;
   }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/os_cpu/linux_x86/linux_x86.ad	Wed May 22 22:06:28 2019 -0400
@@ -0,0 +1,53 @@
+//
+// Copyright (c) 2019, 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.
+//
+//
+
+instruct rseqProcessorId(rRegI dst) %{
+  predicate(os::Linux::supports_rseq());
+  match(Set dst (GetProcessorId));
+  effect(DEF dst);
+  ins_cost(125);
+
+  ins_encode %{
+    Register Rdst = $dst$$Register;
+    __ rseq_cpuid(Rdst);
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
+
+instruct compareAndSwapLCPU(rRegI res, memory mem_ptr, rRegI cpu, rRegL oldval, rRegL newval,
+  rRegP tmp,
+  rFlagsReg cr)
+%{
+  predicate(os::Linux::supports_rseq());
+  match(Set res (CompareAndSwapLCPU mem_ptr (Binary (Binary oldval newval) cpu)));
+  effect(TEMP tmp, KILL cr);
+  ins_cost(500);
+
+  ins_encode %{
+    __ compareAndSetLCPU($res$$Register, $mem_ptr$$Address, $cpu$$Register,
+       $oldval$$Register,  $newval$$Register, $tmp$$Register);
+    // Need volatile barrier here?
+  %}
+  ins_pipe(ialu_reg_mem);
+%}
--- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.hpp	Wed May 22 22:06:28 2019 -0400
@@ -49,6 +49,13 @@
    */
   static void workaround_expand_exec_shield_cs_limit();
 
+#define PLATFORM_GET_PROCESSOR_ID
   static int getProcessorId();
 
+#if defined(__NR_rseq)
+#define PLATFORM_SUPPORTS_RSEQ
+  static bool supports_rseq() { return os::Linux::supports_rseq(); }
+  static bool compareAndSetLongCPU(JavaThread *thread, volatile jlong* addr, jlong offset, int cpu, jlong e, jlong x);
+#endif
+
 #endif // OS_CPU_LINUX_X86_OS_LINUX_X86_HPP
--- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.inline.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.inline.hpp	Wed May 22 22:06:28 2019 -0400
@@ -26,6 +26,7 @@
 #define OS_CPU_LINUX_X86_OS_LINUX_X86_INLINE_HPP
 
 #include "runtime/os.hpp"
+#include "runtime/thread.hpp"
 
 // See http://www.technovelty.org/code/c/reading-rdtsc.htl for details
 inline jlong os::rdtsc() {
@@ -43,4 +44,51 @@
 #endif // AMD64
 }
 
+#if defined(__NR_rseq)
+inline bool os::compareAndSetLongCPU(JavaThread *thread, volatile jlong* addr, jlong offset, int cpu, jlong e, jlong x) {
+  register void *tmp = NULL;
+  __asm__ volatile goto (
+  ".pushsection rseq_cs, \"ax\"\n\t"
+  ".balign 32\n\t"	
+  "Lcs:\n\t"
+  ".long 0x0, 0x0\n\t"
+  ".quad Lstart_ip, (Lpost_commit_offset-Lstart_ip), Labort\n\t"
+  ".popsection\n\t"
+
+  "leaq Lcs(%%rip), %[tmp]\n\t"
+  "movq %[tmp], %[rseq_cs]\n\t"
+  "Lstart_ip:\n\t"
+
+  "cmpl %[cpu_id], %[current_cpu_id]\n\t"
+  "jne %l[fail]\n\t"
+
+  "cmpq %[mp], %[e]\n\t"
+  "jne %l[fail]\n\t"
+
+  "movq %[x], %[mp]\n\t"
+  "Lpost_commit_offset:\n\t"
+
+  ".pushsection rseq_abort, \"ax\"\n\t"
+  ".long 0x7ff7effe\n\t"
+  "Labort:\n\t"
+  "jmp %l[fail]\n\t"
+  ".popsection\n\t"
+  :
+  : [rseq_cs] "m" (thread->rs.rseq_cs),
+    [tmp] "r" (tmp),
+    [mp] "m" (*(volatile jlong *)addr),
+    [offset] "r" (offset),
+    [current_cpu_id] "m" (thread->rs.cpu_id),
+    [cpu_id]  "r" (cpu),
+    [e]  "r" (e),
+    [x]  "r" (x)
+  : "memory", "rax", "cc"
+  : fail);
+  // Need volatile barrier here?
+  return true;
+fail:
+  return false;
+}
+#endif
+
 #endif // OS_CPU_LINUX_X86_OS_LINUX_X86_INLINE_HPP
--- a/src/hotspot/os_cpu/linux_x86/thread_linux_x86.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_x86/thread_linux_x86.hpp	Wed May 22 22:06:28 2019 -0400
@@ -25,8 +25,11 @@
 #ifndef OS_CPU_LINUX_X86_THREAD_LINUX_X86_HPP
 #define OS_CPU_LINUX_X86_THREAD_LINUX_X86_HPP
 
+#include "thread_linux.hpp"
+
  private:
   void pd_initialize() {
+    pd_linux_initialize();
     _anchor.clear();
   }
 
--- a/src/hotspot/os_cpu/linux_zero/thread_linux_zero.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/os_cpu/linux_zero/thread_linux_zero.hpp	Wed May 22 22:06:28 2019 -0400
@@ -26,11 +26,14 @@
 #ifndef OS_CPU_LINUX_ZERO_THREAD_LINUX_ZERO_HPP
 #define OS_CPU_LINUX_ZERO_THREAD_LINUX_ZERO_HPP
 
+#include "thread_linux.hpp"
+
  private:
   ZeroStack  _zero_stack;
   ZeroFrame* _top_zero_frame;
 
   void pd_initialize() {
+    pd_linux_initialize();
     _top_zero_frame = NULL;
   }
 
--- a/src/hotspot/share/adlc/formssel.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/adlc/formssel.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2019, 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
@@ -3502,6 +3502,7 @@
     "WeakCompareAndSwapB", "WeakCompareAndSwapS", "WeakCompareAndSwapI", "WeakCompareAndSwapL", "WeakCompareAndSwapP", "WeakCompareAndSwapN",
     "CompareAndExchangeB", "CompareAndExchangeS", "CompareAndExchangeI", "CompareAndExchangeL", "CompareAndExchangeP", "CompareAndExchangeN",
     "ShenandoahCompareAndSwapN", "ShenandoahCompareAndSwapP", "ShenandoahWeakCompareAndSwapP", "ShenandoahWeakCompareAndSwapN", "ShenandoahCompareAndExchangeP", "ShenandoahCompareAndExchangeN",
+    "CompareAndSwapLCPU",
     "StoreCM",
     "ClearArray",
     "GetAndSetB", "GetAndSetS", "GetAndAddI", "GetAndSetI", "GetAndSetP",
--- a/src/hotspot/share/c1/c1_Compiler.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/c1/c1_Compiler.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -225,10 +225,19 @@
   case vmIntrinsics::_getEventWriter:
 #if defined(_LP64) || !defined(TRACE_ID_SHIFT)
   case vmIntrinsics::_getClassId:
+#endif
+#endif
+#ifdef C1_GET_PROCESSOR_ID
   case vmIntrinsics::_getProcessorId:
+    break;
 #endif
+#ifdef C1_CMP_SET_CPU
+  case vmIntrinsics::_compareAndSetLongCPU:
+    if (!C1_MacroAssembler::supports_cmp_set_cpu()) {
+      return false;
+    }
+    break;
 #endif
-    break;
   default:
     return false; // Intrinsics not on the previous list are not available.
   }
--- a/src/hotspot/share/c1/c1_LIR.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/c1/c1_LIR.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -865,6 +865,7 @@
 // LIR_OpCompareAndSwap
     case lir_cas_long:
     case lir_cas_obj:
+    case lir_cas_long_cpu:
     case lir_cas_int: {
       assert(op->as_OpCompareAndSwap() != NULL, "must be");
       LIR_OpCompareAndSwap* opCompareAndSwap = (LIR_OpCompareAndSwap*)op;
@@ -879,14 +880,21 @@
                                                       do_temp(opCompareAndSwap->_cmp_value);
                                                       do_input(opCompareAndSwap->_new_value);
                                                       do_temp(opCompareAndSwap->_new_value);
+      if (opCompareAndSwap->_cpu->is_valid()) {
+                                         	      do_input(opCompareAndSwap->_offset);
+                                         	      do_temp(opCompareAndSwap->_offset);
+                                         	      do_input(opCompareAndSwap->_cpu);
+                                         	      do_temp(opCompareAndSwap->_cpu);
+      }
       if (opCompareAndSwap->_tmp1->is_valid())        do_temp(opCompareAndSwap->_tmp1);
       if (opCompareAndSwap->_tmp2->is_valid())        do_temp(opCompareAndSwap->_tmp2);
-      if (opCompareAndSwap->_result->is_valid())      do_output(opCompareAndSwap->_result);
-
+      if (opCompareAndSwap->_result->is_valid())      {
+	                                              do_output(opCompareAndSwap->_result);
+	                                              do_temp(opCompareAndSwap->_result);
+      }
       break;
     }
 
-
 // LIR_OpAllocArray;
     case lir_alloc_array: {
       assert(op->as_OpAllocArray() != NULL, "must be");
@@ -1441,6 +1449,11 @@
   }
 }
 
+void LIR_List::cas_long_cpu(LIR_Opr addr, LIR_Opr off, LIR_Opr cmp_value, LIR_Opr new_value,
+                        LIR_Opr t1, LIR_Opr t2, LIR_Opr cpu, LIR_Opr result) {
+  append(new LIR_OpCompareAndSwap(lir_cas_long_cpu, addr, off, cmp_value, new_value, t1, t2, cpu, result));
+}
+
 void LIR_List::cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
                         LIR_Opr t1, LIR_Opr t2, LIR_Opr result) {
   append(new LIR_OpCompareAndSwap(lir_cas_long, addr, cmp_value, new_value, t1, t2, result));
@@ -1738,6 +1751,7 @@
      case lir_cas_long:              s = "cas_long";      break;
      case lir_cas_obj:               s = "cas_obj";      break;
      case lir_cas_int:               s = "cas_int";      break;
+     case lir_cas_long_cpu:          s = "cas_long_cpu"; break;
      // LIR_OpProfileCall
      case lir_profile_call:          s = "profile_call";  break;
      // LIR_OpProfileType
--- a/src/hotspot/share/c1/c1_LIR.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/c1/c1_LIR.hpp	Wed May 22 22:06:28 2019 -0400
@@ -988,6 +988,7 @@
     , lir_cas_long
     , lir_cas_obj
     , lir_cas_int
+    , lir_cas_long_cpu
   , end_opCompareAndSwap
   , begin_opMDOProfile
     , lir_profile_call
@@ -1856,6 +1857,9 @@
   LIR_Opr _addr;
   LIR_Opr _cmp_value;
   LIR_Opr _new_value;
+  LIR_Opr _cpu;
+  LIR_Opr _offset;
+  LIR_Opr _result;
   LIR_Opr _tmp1;
   LIR_Opr _tmp2;
 
@@ -1866,12 +1870,30 @@
     , _addr(addr)
     , _cmp_value(cmp_value)
     , _new_value(new_value)
+    , _cpu(LIR_OprFact::illegalOpr)
+    , _offset(LIR_OprFact::illegalOpr)
+    , _result(result)
+    , _tmp1(t1)
+    , _tmp2(t2)                                  { }
+
+  LIR_OpCompareAndSwap(LIR_Code code, LIR_Opr obj, LIR_Opr off, LIR_Opr cmp_value, LIR_Opr new_value,
+                       LIR_Opr t1, LIR_Opr t2, LIR_Opr cpu, LIR_Opr result)
+    : LIR_Op(code, result, NULL)  // no result, no info
+    , _addr(obj)
+    , _cmp_value(cmp_value)
+    , _new_value(new_value)
+    , _cpu(cpu)
+    , _offset(off)
+    , _result(result)
     , _tmp1(t1)
     , _tmp2(t2)                                  { }
 
   LIR_Opr addr()        const                    { return _addr;  }
+  LIR_Opr offset()      const                    { return _offset;  }
+  LIR_Opr cpu()         const                    { return _cpu;  }
   LIR_Opr cmp_value()   const                    { return _cmp_value; }
   LIR_Opr new_value()   const                    { return _new_value; }
+  LIR_Opr result()      const                    { return _result; }
   LIR_Opr tmp1()        const                    { return _tmp1;      }
   LIR_Opr tmp2()        const                    { return _tmp2;      }
 
@@ -2148,6 +2170,8 @@
     append(new LIR_Op2(lir_cmove, condition, src1, src2, dst, type));
   }
 
+  void cas_long_cpu(LIR_Opr addr, LIR_Opr off, LIR_Opr cmp_value, LIR_Opr new_value,
+                LIR_Opr t1, LIR_Opr t2, LIR_Opr cpu, LIR_Opr result);
   void cas_long(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
                 LIR_Opr t1, LIR_Opr t2, LIR_Opr result = LIR_OprFact::illegalOpr);
   void cas_obj(LIR_Opr addr, LIR_Opr cmp_value, LIR_Opr new_value,
--- a/src/hotspot/share/c1/c1_LIRAssembler.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -767,9 +767,11 @@
       atomic_op(op->code(), op->in_opr1(), op->in_opr2(), op->result_opr(), op->tmp1_opr());
       break;
 
+#ifdef C1_GET_PROCESSOR_ID
     case lir_getprocessorid:
       getprocessorid(op->result_opr(), op->in_opr1(), op->in_opr2());
       break;
+#endif
 
     default:
       Unimplemented();
--- a/src/hotspot/share/c1/c1_LIRAssembler.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp	Wed May 22 22:06:28 2019 -0400
@@ -115,6 +115,9 @@
 
   void getprocessorid(LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2);
 
+  void compareAndSetLCPU(LIR_Opr result, LIR_Opr obj, LIR_Opr offset,
+                         LIR_Opr cpu, LIR_Opr oldval, LIR_Opr newval);
+
   // patching
   void append_patching_stub(PatchingStub* stub);
   void patching_epilog(PatchingStub* patch, LIR_PatchCode patch_code, Register obj, CodeEmitInfo* info);
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2019, 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
@@ -29,6 +29,7 @@
 #include "c1/c1_Instruction.hpp"
 #include "c1/c1_LIRAssembler.hpp"
 #include "c1/c1_LIRGenerator.hpp"
+#include "c1/c1_MacroAssembler.hpp"
 #include "c1/c1_ValueStack.hpp"
 #include "ci/ciArrayKlass.hpp"
 #include "ci/ciInstance.hpp"
@@ -3098,9 +3099,17 @@
     do_vectorizedMismatch(x);
     break;
 
+#ifdef C1_GET_PROCESSOR_ID
   case vmIntrinsics::_getProcessorId:
     do_getProcessorId(x);
     break;
+#endif
+
+#ifdef C1_CMP_SET_CPU
+  case vmIntrinsics::_compareAndSetLongCPU:
+    do_compareAndSetLCPU(x);
+    break;
+#endif
 
   default: ShouldNotReachHere(); break;
   }
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp	Wed May 22 22:06:28 2019 -0400
@@ -266,6 +266,7 @@
   void do_update_CRC32C(Intrinsic* x);
   void do_vectorizedMismatch(Intrinsic* x);
   void do_getProcessorId(Intrinsic* x);
+  void do_compareAndSetLCPU(Intrinsic* x);
 
  public:
   LIR_Opr call_runtime(BasicTypeArray* signature, LIRItemList* args, address entry, ValueType* result_type, CodeEmitInfo* info);
--- a/src/hotspot/share/c1/c1_MacroAssembler.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/c1/c1_MacroAssembler.hpp	Wed May 22 22:06:28 2019 -0400
@@ -48,6 +48,10 @@
 
 #include CPU_HEADER(c1_MacroAssembler)
 
+#ifndef C1_CMP_SET_CPU
+  static bool supports_cmp_set_cpu() { return false; }
+#endif
+
 };
 
 
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Wed May 22 22:06:28 2019 -0400
@@ -1253,6 +1253,7 @@
                                                                                                                         \
   do_signature(compareAndSetReference_signature,      "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z")        \
   do_signature(compareAndExchangeReference_signature, "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \
+  do_signature(compareAndSetLongCPU_signature,        "(Ljava/lang/Object;JIJJ)Z")                                      \
   do_signature(compareAndSetLong_signature,        "(Ljava/lang/Object;JJJ)Z")                                          \
   do_signature(compareAndExchangeLong_signature,   "(Ljava/lang/Object;JJJ)J")                                          \
   do_signature(compareAndSetInt_signature,         "(Ljava/lang/Object;JII)Z")                                          \
@@ -1266,6 +1267,7 @@
   do_name(compareAndExchangeReference_name,         "compareAndExchangeReference")                                      \
   do_name(compareAndExchangeReferenceAcquire_name,  "compareAndExchangeReferenceAcquire")                               \
   do_name(compareAndExchangeReferenceRelease_name,  "compareAndExchangeReferenceRelease")                               \
+  do_name(compareAndSetLongCPU_name,                "compareAndSetLongCPU")                                             \
   do_name(compareAndSetLong_name,                   "compareAndSetLong")                                                \
   do_name(compareAndExchangeLong_name,              "compareAndExchangeLong")                                           \
   do_name(compareAndExchangeLongAcquire_name,       "compareAndExchangeLongAcquire")                                    \
@@ -1308,6 +1310,7 @@
   do_intrinsic(_compareAndExchangeReference,         jdk_internal_misc_Unsafe,  compareAndExchangeReference_name,         compareAndExchangeReference_signature, F_RN) \
   do_intrinsic(_compareAndExchangeReferenceAcquire,  jdk_internal_misc_Unsafe,  compareAndExchangeReferenceAcquire_name,  compareAndExchangeReference_signature, F_R)  \
   do_intrinsic(_compareAndExchangeReferenceRelease,  jdk_internal_misc_Unsafe,  compareAndExchangeReferenceRelease_name,  compareAndExchangeReference_signature, F_R)  \
+  do_intrinsic(_compareAndSetLongCPU,             jdk_internal_misc_Unsafe,  compareAndSetLongCPU_name,             compareAndSetLongCPU_signature,     F_RN) \
   do_intrinsic(_compareAndSetLong,                jdk_internal_misc_Unsafe,  compareAndSetLong_name,                compareAndSetLong_signature,        F_RN) \
   do_intrinsic(_compareAndExchangeLong,           jdk_internal_misc_Unsafe,  compareAndExchangeLong_name,           compareAndExchangeLong_signature,   F_RN) \
   do_intrinsic(_compareAndExchangeLongAcquire,    jdk_internal_misc_Unsafe,  compareAndExchangeLongAcquire_name,    compareAndExchangeLong_signature,   F_R)  \
--- a/src/hotspot/share/code/relocInfo.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/code/relocInfo.cpp	Wed May 22 22:06:28 2019 -0400
@@ -354,6 +354,10 @@
   // The enhanced use of pd_call_destination sorts this all out.
   address orig_addr = old_addr_for(addr(), src, dest);
   address callee    = pd_call_destination(orig_addr);
+  // Jump between sections?
+  if (src->contains(callee)) {
+    callee = new_addr_for(callee, src, dest);
+  }
   // Reassert the callee address, this time in the new copy of the code.
   pd_set_call_destination(callee);
 }
--- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -28,6 +28,7 @@
 #include "opto/convertnode.hpp"
 #include "opto/graphKit.hpp"
 #include "opto/idealKit.hpp"
+#include "opto/intrinsicnode.hpp"
 #include "opto/macro.hpp"
 #include "opto/narrowptrnode.hpp"
 #include "utilities/macros.hpp"
@@ -449,7 +450,8 @@
 }
 
 Node* BarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
-                                                    Node* new_val, const Type* value_type) const {
+                                                    Node* new_val, Node* cpu,
+						    const Type* value_type) const {
   GraphKit* kit = access.kit();
   DecoratorSet decorators = access.decorators();
   MemNode::MemOrd mo = access.mem_node_mo();
@@ -507,7 +509,11 @@
         if (is_weak_cas) {
           load_store = kit->gvn().transform(new WeakCompareAndSwapLNode(kit->control(), mem, adr, new_val, expected_val, mo));
         } else {
-          load_store = kit->gvn().transform(new CompareAndSwapLNode(kit->control(), mem, adr, new_val, expected_val, mo));
+          if (cpu != NULL) {
+            load_store = kit->gvn().transform(new CompareAndSwapLCPUNode(kit->control(), mem, adr, new_val, expected_val, cpu, mo));
+          } else {
+            load_store = kit->gvn().transform(new CompareAndSwapLNode(kit->control(), mem, adr, new_val, expected_val, mo));
+          }
         }
         break;
       }
@@ -608,10 +614,11 @@
 }
 
 Node* BarrierSetC2::atomic_cmpxchg_bool_at(C2AtomicParseAccess& access, Node* expected_val,
-                                           Node* new_val, const Type* value_type) const {
+                                           Node* new_val, Node* cpu,
+                                           const Type* value_type) const {
   C2AccessFence fence(access);
   resolve_address(access);
-  return atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
+  return atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, cpu, value_type);
 }
 
 Node* BarrierSetC2::atomic_xchg_at(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const {
--- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -224,7 +224,8 @@
   virtual Node* atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
                                                Node* new_val, const Type* val_type) const;
   virtual Node* atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
-                                                Node* new_val, const Type* value_type) const;
+                                                Node* new_val, Node* cpu,
+                                                const Type* value_type) const;
   virtual Node* atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* val_type) const;
   virtual Node* atomic_add_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* val_type) const;
   void pin_atomic_op(C2AtomicParseAccess& access) const;
@@ -237,7 +238,8 @@
   virtual Node* atomic_cmpxchg_val_at(C2AtomicParseAccess& access, Node* expected_val,
                                       Node* new_val, const Type* val_type) const;
   virtual Node* atomic_cmpxchg_bool_at(C2AtomicParseAccess& access, Node* expected_val,
-                                       Node* new_val, const Type* val_type) const;
+                                       Node* new_val, Node* cpu,
+                                       const Type* val_type) const;
   virtual Node* atomic_xchg_at(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const;
   virtual Node* atomic_add_at(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const;
 
--- a/src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -83,18 +83,19 @@
 }
 
 Node* ModRefBarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
-                                                          Node* new_val, const Type* value_type) const {
+                                                          Node* new_val, Node* cpu,
+                                                          const Type* value_type) const {
   GraphKit* kit = access.kit();
 
   if (!access.is_oop()) {
-    return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
+    return BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, cpu, value_type);
   }
 
   pre_barrier(kit, false /* do_load */,
               kit->control(), NULL, NULL, max_juint, NULL, NULL,
               expected_val /* pre_val */, T_OBJECT);
 
-  Node* load_store = BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
+  Node* load_store = BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, cpu, value_type);
 
   // Emit the post barrier only when the actual store happened. This makes sense
   // to check only for LS_cmp_* that can fail to set the value.
--- a/src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/gc/shared/c2/modRefBarrierSetC2.hpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -57,7 +57,8 @@
   virtual Node* atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
                                                Node* new_val, const Type* value_type) const;
   virtual Node* atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
-                                                Node* new_val, const Type* value_type) const;
+                                                Node* new_val, Node* cpu,
+                                                const Type* value_type) const;
   virtual Node* atomic_xchg_at_resolved(C2AtomicParseAccess& access, Node* new_val, const Type* value_type) const;
 };
 
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp	Wed May 22 22:06:28 2019 -0400
@@ -744,8 +744,9 @@
 }
 
 Node* ZBarrierSetC2::atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access, Node* expected_val,
-                                                     Node* new_val, const Type* value_type) const {
-  Node* result = BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, value_type);
+                                                     Node* new_val, Node* cpu,
+                                                     const Type* value_type) const {
+  Node* result = BarrierSetC2::atomic_cmpxchg_bool_at_resolved(access, expected_val, new_val, cpu, value_type);
   if (!barrier_needed(access)) {
     return result;
   }
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp	Wed May 22 22:06:28 2019 -0400
@@ -180,6 +180,7 @@
   virtual Node* atomic_cmpxchg_bool_at_resolved(C2AtomicParseAccess& access,
                                                 Node* expected_val,
                                                 Node* new_val,
+                                                Node* cpu,
                                                 const Type* value_type) const;
   virtual Node* atomic_xchg_at_resolved(C2AtomicParseAccess& access,
                                         Node* new_val,
--- a/src/hotspot/share/opto/c2compiler.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/c2compiler.cpp	Wed May 22 22:06:28 2019 -0400
@@ -624,6 +624,9 @@
   case vmIntrinsics::_Preconditions_checkIndex:
   case vmIntrinsics::_getProcessorId:
     break;
+  case vmIntrinsics::_compareAndSetLongCPU:
+    if (!Matcher::match_rule_supported(Op_CompareAndSwapLCPU)) return false;
+    break;
   default:
     return false;
   }
--- a/src/hotspot/share/opto/classes.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/classes.hpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -85,6 +85,7 @@
 macro(CmpP)
 macro(CmpU)
 macro(CmpUL)
+macro(CompareAndSwapLCPU)
 macro(CompareAndSwapB)
 macro(CompareAndSwapS)
 macro(CompareAndSwapI)
--- a/src/hotspot/share/opto/compile.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/compile.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -2944,6 +2944,7 @@
   case Op_CompareAndExchangeL:
   case Op_CompareAndExchangeP:
   case Op_CompareAndExchangeN:
+  case Op_CompareAndSwapLCPU:
   case Op_GetAndAddS:
   case Op_GetAndAddB:
   case Op_GetAndAddI:
--- a/src/hotspot/share/opto/graphKit.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/graphKit.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1640,6 +1640,7 @@
                                               int alias_idx,
                                               Node* expected_val,
                                               Node* new_val,
+                                              Node* cpu,
                                               const Type* value_type,
                                               BasicType bt,
                                               DecoratorSet decorators) {
@@ -1647,9 +1648,9 @@
   C2AtomicParseAccess access(this, decorators | C2_READ_ACCESS | C2_WRITE_ACCESS,
                         bt, obj, addr, alias_idx);
   if (access.is_raw()) {
-    return _barrier_set->BarrierSetC2::atomic_cmpxchg_bool_at(access, expected_val, new_val, value_type);
+    return _barrier_set->BarrierSetC2::atomic_cmpxchg_bool_at(access, expected_val, new_val, cpu, value_type);
   } else {
-    return _barrier_set->atomic_cmpxchg_bool_at(access, expected_val, new_val, value_type);
+    return _barrier_set->atomic_cmpxchg_bool_at(access, expected_val, new_val, cpu, value_type);
   }
 }
 
--- a/src/hotspot/share/opto/graphKit.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/graphKit.hpp	Wed May 22 22:06:28 2019 -0400
@@ -610,6 +610,7 @@
                                       int alias_idx,
                                       Node* expected_val,
                                       Node* new_val,
+                                      Node* cpu,
                                       const Type* value_type,
                                       BasicType bt,
                                       DecoratorSet decorators);
--- a/src/hotspot/share/opto/intrinsicnode.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/intrinsicnode.hpp	Wed May 22 22:06:28 2019 -0400
@@ -25,6 +25,7 @@
 #ifndef SHARE_OPTO_INTRINSICNODE_HPP
 #define SHARE_OPTO_INTRINSICNODE_HPP
 
+#include "opto/memnode.hpp"
 #include "opto/node.hpp"
 #include "opto/opcodes.hpp"
 
@@ -227,4 +228,21 @@
   virtual uint ideal_reg() const { return Op_RegI; }
 };
 
+// Restartable Sequences
+class CompareAndSwapLCPUNode : public CompareAndSwapLNode {
+
+public:
+  enum {
+    CpuIn = ExpectedIn+1, // One more input than CompareAndSwapNode
+    NumIn
+  };
+
+  CompareAndSwapLCPUNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex, Node *cpu, MemNode::MemOrd mem_ord) : CompareAndSwapLNode(c, mem, adr, val, ex, mem_ord, NumIn)
+  {
+    init_req(CpuIn, cpu);
+  }
+
+  virtual int Opcode() const;
+};
+
 #endif // SHARE_OPTO_INTRINSICNODE_HPP
--- a/src/hotspot/share/opto/library_call.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/library_call.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2019, 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
@@ -283,7 +283,7 @@
                                       uint new_idx);
 
   typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind;
-  bool inline_unsafe_load_store(BasicType type,  LoadStoreKind kind, AccessKind access_kind);
+  bool inline_unsafe_load_store(BasicType type,  LoadStoreKind kind, AccessKind access_kind, bool cpu = false);
   bool inline_unsafe_fence(vmIntrinsics::ID id);
   bool inline_onspinwait();
   bool inline_fp_conversions(vmIntrinsics::ID id);
@@ -686,6 +686,8 @@
   case vmIntrinsics::_compareAndSetInt:         return inline_unsafe_load_store(T_INT,    LS_cmp_swap,      Volatile);
   case vmIntrinsics::_compareAndSetLong:        return inline_unsafe_load_store(T_LONG,   LS_cmp_swap,      Volatile);
 
+  case vmIntrinsics::_compareAndSetLongCPU:     return inline_unsafe_load_store(T_LONG,   LS_cmp_swap,      Volatile, true /* cpu */);
+
   case vmIntrinsics::_weakCompareAndSetReferencePlain:     return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Relaxed);
   case vmIntrinsics::_weakCompareAndSetReferenceAcquire:   return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Acquire);
   case vmIntrinsics::_weakCompareAndSetReferenceRelease:   return inline_unsafe_load_store(T_OBJECT, LS_cmp_swap_weak, Release);
@@ -2585,7 +2587,7 @@
 //   long   getAndSet(Object o, long offset, long   newValue)
 //   Object getAndSet(Object o, long offset, Object newValue)
 //
-bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadStoreKind kind, const AccessKind access_kind) {
+bool LibraryCallKit::inline_unsafe_load_store(const BasicType type, const LoadStoreKind kind, const AccessKind access_kind, bool is_cpu) {
   // This basic scheme here is the same as inline_unsafe_access, but
   // differs in enough details that combining them would make the code
   // overly confusing.  (This is a true fact! I originally combined
@@ -2624,7 +2626,11 @@
       // Check the signatures.
 #ifdef ASSERT
       assert(rtype == T_BOOLEAN, "CAS must return boolean");
-      assert(sig->count() == 4, "CAS has 4 arguments");
+      if (is_cpu) {
+        assert(sig->count() == 5, "CAS-CPU has 5 arguments");
+      } else {
+        assert(sig->count() == 4, "CAS has 4 arguments");
+      }
       assert(sig->type_at(0)->basic_type() == T_OBJECT, "CAS base is object");
       assert(sig->type_at(1)->basic_type() == T_LONG, "CAS offset is long");
 #endif // ASSERT
@@ -2654,6 +2660,7 @@
   Node* offset   = NULL;
   Node* oldval   = NULL;
   Node* newval   = NULL;
+  Node* cpu      = NULL;
   switch(kind) {
     case LS_cmp_swap:
     case LS_cmp_swap_weak:
@@ -2662,8 +2669,10 @@
       receiver = argument(0);  // type: oop
       base     = argument(1);  // type: oop
       offset   = argument(2);  // type: long
-      oldval   = argument(4);  // type: oop, int, or long
-      newval   = argument(two_slot_type ? 6 : 5);  // type: oop, int, or long
+      if (is_cpu) cpu = argument(4);
+      int old_index = is_cpu ? 5 : 4;
+      oldval   = argument(old_index);  // type: oop, int, or long
+      newval   = argument(two_slot_type ? old_index + 2 : old_index + 1);  // type: oop, int, or long
       break;
     }
     case LS_get_add:
@@ -2755,7 +2764,7 @@
       decorators |= C2_WEAK_CMPXCHG;
     case LS_cmp_swap: {
       result = access_atomic_cmpxchg_bool_at(base, adr, adr_type, alias_idx,
-                                             oldval, newval, value_type, type, decorators);
+                                             oldval, newval, cpu, value_type, type, decorators);
       break;
     }
     case LS_get_set: {
--- a/src/hotspot/share/opto/matcher.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/matcher.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -31,6 +31,7 @@
 #include "opto/addnode.hpp"
 #include "opto/callnode.hpp"
 #include "opto/idealGraphPrinter.hpp"
+#include "opto/intrinsicnode.hpp"
 #include "opto/matcher.hpp"
 #include "opto/memnode.hpp"
 #include "opto/movenode.hpp"
@@ -2261,6 +2262,18 @@
 
 void Matcher::find_shared_post_visit(Node* n, uint opcode) {
   switch(opcode) {       // Handle some opcodes special
+    case Op_CompareAndSwapLCPU: {
+      Node* mem    = n->in(MemNode::Address);
+      Node* newval = n->in(MemNode::ValueIn);
+      Node* oldval = n->in(LoadStoreConditionalNode::ExpectedIn);
+      Node* cpu    = n->in(CompareAndSwapLCPUNode::CpuIn);
+      Node* pair2 = new BinaryNode(oldval, newval);
+      Node* pair1 = new BinaryNode(pair2, cpu);
+      n->set_req(MemNode::ValueIn, pair1);
+      n->del_req(CompareAndSwapLCPUNode::CpuIn);
+      n->del_req(LoadStoreConditionalNode::ExpectedIn);
+      break;
+    }
     case Op_StorePConditional:
     case Op_StoreIConditional:
     case Op_StoreLConditional:
--- a/src/hotspot/share/opto/memnode.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/memnode.cpp	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -2852,7 +2852,7 @@
 
 //=============================================================================
 //----------------------------------LoadStoreConditionalNode--------------------
-LoadStoreConditionalNode::LoadStoreConditionalNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex ) : LoadStoreNode(c, mem, adr, val, NULL, TypeInt::BOOL, 5) {
+LoadStoreConditionalNode::LoadStoreConditionalNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, uint required ) : LoadStoreNode(c, mem, adr, val, NULL, TypeInt::BOOL, required) {
   init_req(ExpectedIn, ex );
 }
 
--- a/src/hotspot/share/opto/memnode.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/opto/memnode.hpp	Wed May 22 22:06:28 2019 -0400
@@ -829,7 +829,7 @@
   enum {
     ExpectedIn = MemNode::ValueIn+1 // One more input than MemNode
   };
-  LoadStoreConditionalNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex);
+  LoadStoreConditionalNode(Node *c, Node *mem, Node *adr, Node *val, Node *ex, uint required = 5);
 };
 
 //------------------------------StorePConditionalNode---------------------------
@@ -870,6 +870,7 @@
   const MemNode::MemOrd _mem_ord;
 public:
   CompareAndSwapNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : LoadStoreConditionalNode(c, mem, adr, val, ex), _mem_ord(mem_ord) {}
+  CompareAndSwapNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord, uint required) : LoadStoreConditionalNode(c, mem, adr, val, ex, required), _mem_ord(mem_ord) {}
   MemNode::MemOrd order() const {
     return _mem_ord;
   }
@@ -917,6 +918,7 @@
 class CompareAndSwapLNode : public CompareAndSwapNode {
 public:
   CompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord) { }
+  CompareAndSwapLNode( Node *c, Node *mem, Node *adr, Node *val, Node *ex, MemNode::MemOrd mem_ord, uint required) : CompareAndSwapNode(c, mem, adr, val, ex, mem_ord, required) { }
   virtual int Opcode() const;
 };
 
--- a/src/hotspot/share/prims/unsafe.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/prims/unsafe.cpp	Wed May 22 22:06:28 2019 -0400
@@ -42,6 +42,7 @@
 #include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/jniHandles.inline.hpp"
 #include "runtime/orderAccess.hpp"
+#include "runtime/os.inline.hpp"
 #include "runtime/reflection.hpp"
 #include "runtime/thread.hpp"
 #include "runtime/threadSMR.hpp"
@@ -303,9 +304,16 @@
   return UseUnalignedAccesses;
 } UNSAFE_END
 
+#ifdef PLATFORM_GET_PROCESSOR_ID
 UNSAFE_LEAF(jint, Unsafe_getProcessorId(JNIEnv *env, jobject unsafe)) {
   return os::getProcessorId();
 } UNSAFE_END
+#else
+UNSAFE_ENTRY(jint, Unsafe_getProcessorId(JNIEnv *env, jobject unsafe)) {
+  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "Unsafe.getProcessorId not supported");
+  return -1;
+} UNSAFE_END
+#endif
 
 #define DEFINE_GETSETOOP(java_type, Type) \
  \
@@ -931,6 +939,32 @@
   }
 } UNSAFE_END
 
+#if defined(PLATFORM_SUPPORTS_RSEQ)
+UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetLongCPU(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, int cpu, jlong e, jlong x)) {
+  if (!os::supports_rseq()) {
+    THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "Unsafe.compareAndSetLongCPU not supported");
+    return false;
+  }
+
+  oop p = JNIHandles::resolve(obj);
+  volatile jlong* addr;
+  if (p == NULL) {
+    addr = (volatile jlong *)p->field_addr(offset);
+    assert_field_offset_sane(p, offset);
+  } else {
+    addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset);
+  }
+  JavaThread* thread = JavaThread::thread_from_jni_environment(env);
+  return os::compareAndSetLongCPU(thread, addr, offset, cpu, e, x);
+} UNSAFE_END
+#else
+UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetLongCPU(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, int cpu, jlong e, jlong x)) {
+  assert(!os::supports_rseq(), "something is wrong");
+  THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "Unsafe.compareAndSetLongCPU not supported");
+  return false;
+} UNSAFE_END
+#endif
+
 static void post_thread_park_event(EventThreadPark* event, const oop obj, jlong timeout_nanos, jlong until_epoch_millis) {
   assert(event != NULL, "invariant");
   assert(event->should_commit(), "invariant");
@@ -1085,6 +1119,7 @@
     {CC "compareAndSetReference",CC "(" OBJ "J" OBJ "" OBJ ")Z", FN_PTR(Unsafe_CompareAndSetReference)},
     {CC "compareAndSetInt",   CC "(" OBJ "J""I""I"")Z",  FN_PTR(Unsafe_CompareAndSetInt)},
     {CC "compareAndSetLong",  CC "(" OBJ "J""J""J"")Z",  FN_PTR(Unsafe_CompareAndSetLong)},
+    {CC "compareAndSetLongCPU",  CC "(" OBJ "J""I""J""J"")Z",  FN_PTR(Unsafe_CompareAndSetLongCPU)},
     {CC "compareAndExchangeReference", CC "(" OBJ "J" OBJ "" OBJ ")" OBJ, FN_PTR(Unsafe_CompareAndExchangeReference)},
     {CC "compareAndExchangeInt",  CC "(" OBJ "J""I""I"")I", FN_PTR(Unsafe_CompareAndExchangeInt)},
     {CC "compareAndExchangeLong", CC "(" OBJ "J""J""J"")J", FN_PTR(Unsafe_CompareAndExchangeLong)},
--- a/src/hotspot/share/runtime/os.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/runtime/os.hpp	Wed May 22 22:06:28 2019 -0400
@@ -33,12 +33,17 @@
 #include "utilities/exceptions.hpp"
 #include "utilities/ostream.hpp"
 #include "utilities/macros.hpp"
+
 #ifndef _WINDOWS
 # include <setjmp.h>
 #endif
 #ifdef __APPLE__
 # include <mach/mach_time.h>
 #endif
+#ifdef LINUX
+#include "os_types_linux.hpp"
+#endif
+
 
 class AgentLibrary;
 class frame;
@@ -844,6 +849,14 @@
     return false;
   }
 #endif
+#ifndef PLATFORM_GET_PROCESSOR_ID
+  // No platform-specific code for getting processor id.
+  static int getProcessorID() { return -1; }
+#endif
+#ifndef PLATFORM_SUPPORTS_RSEQ
+  // No platform-specific code for restartable sequences
+  static bool supports_rseq() { return false; }
+#endif
 
   // debugging support (mostly used by debug.cpp but also fatal error handler)
   static bool find(address pc, outputStream* st = tty); // OS specific function to make sense out of an address
--- a/src/hotspot/share/runtime/thread.cpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/runtime/thread.cpp	Wed May 22 22:06:28 2019 -0400
@@ -172,8 +172,14 @@
 // ======= Thread ========
 // Support for forcing alignment of thread objects for biased locking
 void* Thread::allocate(size_t size, bool throw_excpt, MEMFLAGS flags) {
+  int alignment = 0;
   if (UseBiasedLocking) {
-    const int alignment = markOopDesc::biased_lock_alignment;
+    alignment = markOopDesc::biased_lock_alignment;
+  }
+#ifdef __NR_rseq
+  alignment = MAX2(alignment, (int)(__alignof__ (struct rseq)));
+#endif
+  if (alignment > 0) {
     size_t aligned_size = size + (alignment - sizeof(intptr_t));
     void* real_malloc_addr = throw_excpt? AllocateHeap(aligned_size, flags, CURRENT_PC)
                                           : AllocateHeap(aligned_size, flags, CURRENT_PC,
@@ -2081,6 +2087,8 @@
   // Remove from list of active threads list, and notify VM thread if we are the last non-daemon thread
   Threads::remove(this);
 
+  pd_destroy_self();
+
   if (log_is_enabled(Debug, os, thread, timer)) {
     _timer_exit_phase4.stop();
     ResourceMark rm(this);
@@ -2119,6 +2127,8 @@
 
   BarrierSet::barrier_set()->on_thread_detach(this);
 
+  pd_destroy_self();
+
   Threads::remove(this);
   this->smr_delete();
 }
--- a/src/hotspot/share/runtime/thread.hpp	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/hotspot/share/runtime/thread.hpp	Wed May 22 22:06:28 2019 -0400
@@ -55,6 +55,9 @@
 #if INCLUDE_JFR
 #include "jfr/support/jfrThreadExtension.hpp"
 #endif
+#ifdef LINUX
+#include "thread_types_linux.hpp"
+#endif
 
 
 class SafeThreadsListPtr;
@@ -2059,6 +2062,11 @@
   // Machine dependent stuff
 #include OS_CPU_HEADER(thread)
 
+#ifndef PD_DESTROY_SELF
+ public:
+  void pd_destroy_self() {}
+#endif
+
  public:
   void set_blocked_on_compilation(bool value) {
     _blocked_on_compilation = value;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/LongAdderCPU.java	Wed May 22 22:06:28 2019 -0400
@@ -0,0 +1,251 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Doug Lea with assistance from members of JCP JSR-166
+ * Expert Group and released to the public domain, as explained at
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+package java.util.concurrent.atomic;
+
+import java.io.Serializable;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * One or more variables that together maintain an initially zero
+ * {@code long} sum.  When updates (method {@link #add}) are contended
+ * across threads, the set of variables may grow dynamically to reduce
+ * contention. Method {@link #sum} (or, equivalently, {@link
+ * #longValue}) returns the current total combined across the
+ * variables maintaining the sum.
+ *
+ * <p>This class is usually preferable to {@link AtomicLong} when
+ * multiple threads update a common sum that is used for purposes such
+ * as collecting statistics, not for fine-grained synchronization
+ * control.  Under low update contention, the two classes have similar
+ * characteristics. But under high contention, expected throughput of
+ * this class is significantly higher, at the expense of higher space
+ * consumption.
+ *
+ * <p>LongAdders can be used with a {@link
+ * java.util.concurrent.ConcurrentHashMap} to maintain a scalable
+ * frequency map (a form of histogram or multiset). For example, to
+ * add a count to a {@code ConcurrentHashMap<String,LongAdder> freqs},
+ * initializing if not already present, you can use {@code
+ * freqs.computeIfAbsent(key, k -> new LongAdder()).increment();}
+ *
+ * <p>This class extends {@link Number}, but does <em>not</em> define
+ * methods such as {@code equals}, {@code hashCode} and {@code
+ * compareTo} because instances are expected to be mutated, and so are
+ * not useful as collection keys.
+ *
+ * @since 1.8
+ * @author Doug Lea
+ */
+public class LongAdderCPU extends Striped64 {
+    private static final long serialVersionUID = 7249069246863182397L;
+
+    private static final Unsafe U = Unsafe.getUnsafe();
+
+    /**
+     * Creates a new adder with initial sum of zero.
+     */
+    public LongAdderCPU() {
+    }
+
+    transient volatile Cell[] cpu_cells;
+
+    private synchronized void init_cpu_cells() {
+        if (cpu_cells == null) {
+            Cell[] cc = new Cell[NCPU];
+            for (int i = 0; i < NCPU; ++i) {
+                cc[i] = new Cell(0);
+            }
+            cpu_cells = cc;
+        }
+    }
+
+    /**
+     * Adds the given value.
+     *
+     * @param x the value to add
+     */
+    public void add(long x) {
+        Cell[] cs; long b;
+        if ((cs = cells) != null || !casBase(b = base, b + x)) {
+            if (U.compareAndSetCPUSupported()) {
+                int cpu;
+                Cell[] cc = cpu_cells;
+                if (cc != null) {
+                    // Maximum contention
+                    while (true) {
+                        Cell c = cc[(cpu = U.getProcessorId())];
+                        long v = c.value;
+                        if (c.casCPU(cpu, v, v + x)) {
+                            return;
+                        }
+                    }
+                }
+            }
+
+            Cell c;
+            long v; int m;
+            boolean uncontended = true;
+            if (cs == null || (m = cs.length - 1) < 0 ||
+                (c = cs[getProbe() & m]) == null ||
+                !(uncontended = c.cas(v = c.value, v + x))) {
+                longAccumulate(x, null, uncontended);
+                if (cs != null && cs.length >= NCPU && U.compareAndSetCPUSupported()) {
+                    init_cpu_cells();
+                }
+            }
+        }
+    }
+
+    /**
+     * Equivalent to {@code add(1)}.
+     */
+    public void increment() {
+        add(1L);
+    }
+
+    /**
+     * Returns the current sum.  The returned value is <em>NOT</em> an
+     * atomic snapshot; invocation in the absence of concurrent
+     * updates returns an accurate result, but concurrent updates that
+     * occur while the sum is being calculated might not be
+     * incorporated.
+     *
+     * @return the sum
+     */
+    public long sum() {
+        Cell[] cs = cells;
+        long sum = base;
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    sum += c.value;
+        }
+        cs = cpu_cells;
+        if (cs != null) {
+            for (Cell c : cpu_cells) {
+                sum += c.value;
+            }
+        }
+        return sum;
+    }
+
+    /**
+     * Resets variables maintaining the sum to zero.  This method may
+     * be a useful alternative to creating a new adder, but is only
+     * effective if there are no concurrent updates.  Because this
+     * method is intrinsically racy, it should only be used when it is
+     * known that no threads are concurrently updating.
+     */
+    public void reset() {
+        Cell[] cs = cells;
+        base = 0L;
+        if (cs != null) {
+            for (Cell c : cs)
+                if (c != null)
+                    c.reset();
+        }
+        cs = cpu_cells;
+        cpu_cells = null;
+        if (cs != null) {
+            for (int i = 0; i < NCPU; ++i) {
+                cs[i] = new Cell(0);
+            }
+        }
+    }
+
+    /**
+     * Equivalent in effect to {@link #sum} followed by {@link
+     * #reset}. This method may apply for example during quiescent
+     * points between multithreaded computations.  If there are
+     * updates concurrent with this method, the returned value is
+     * <em>not</em> guaranteed to be the final value occurring before
+     * the reset.
+     *
+     * @return the sum
+     */
+    public long sumThenReset() {
+        Cell[] cs = cells;
+        long sum = getAndSetBase(0L);
+        if (cs != null) {
+            for (Cell c : cs) {
+                if (c != null)
+                    sum += c.getAndSet(0L);
+            }
+        }
+        cs = cpu_cells;
+        cpu_cells = null;
+        if (cs != null) {
+            for (int i = 0; i < NCPU; ++i) {
+                sum += cs[i].value;
+            }
+        }
+        return sum;
+    }
+
+    /**
+     * Equivalent to {@link #sum}.
+     *
+     * @return the sum
+     */
+    public long longValue() {
+        return sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as an {@code int} after a narrowing
+     * primitive conversion.
+     */
+    public int intValue() {
+        return (int)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code float}
+     * after a widening primitive conversion.
+     */
+    public float floatValue() {
+        return (float)sum();
+    }
+
+    /**
+     * Returns the {@link #sum} as a {@code double} after a widening
+     * primitive conversion.
+     */
+    public double doubleValue() {
+        return (double)sum();
+    }
+
+}
--- a/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java	Wed May 22 22:06:28 2019 -0400
@@ -127,6 +127,9 @@
         final boolean cas(long cmp, long val) {
             return VALUE.compareAndSet(this, cmp, val);
         }
+        final boolean casCPU(int cpu, long cmp, long val) {
+	    return U.compareAndSetLongCPU(this, offset, cpu, cmp, val);
+        }
         final void reset() {
             VALUE.setVolatile(this, 0L);
         }
@@ -137,12 +140,16 @@
             return (long)VALUE.getAndSet(this, val);
         }
 
+	private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
+	private static final long offset;
+
         // VarHandle mechanics
         private static final VarHandle VALUE;
         static {
             try {
                 MethodHandles.Lookup l = MethodHandles.lookup();
                 VALUE = l.findVarHandle(Cell.class, "value", long.class);
+		offset = U.objectFieldOffset(Cell.class, "value");
             } catch (ReflectiveOperationException e) {
                 throw new ExceptionInInitializerError(e);
             }
--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Mon Feb 25 18:27:59 2019 +0000
+++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2019, 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
@@ -1911,6 +1911,38 @@
                                                   long expected,
                                                   long x);
 
+    private static final boolean compareAndSetCPUSupported;
+
+    static {
+      boolean supported = false;
+      try {
+          Long[] l = new Long[1];
+          l[0] = 0L;
+          theUnsafe.compareAndSetLongCPU(l, ARRAY_LONG_BASE_OFFSET,
+              theUnsafe.getProcessorId(), 0L, 1L);
+          supported = true;
+      } catch (Throwable t) {
+      } finally {
+          compareAndSetCPUSupported = supported;
+      }
+    }
+
+    /**
+     * @return {@code true} if compareAndSet CPU operations are supported.
+     */
+    public final boolean compareAndSetCPUSupported() {
+        return compareAndSetCPUSupported;
+    }
+
+    /**
+     * @return {@code true} if successful
+     */
+    @HotSpotIntrinsicCandidate
+    public final native boolean compareAndSetLongCPU(Object o, long offset,
+                                                  int cpu,
+                                                  long expected,
+                                                  long x);
+
     @HotSpotIntrinsicCandidate
     public final native long compareAndExchangeLong(Object o, long offset,
                                                     long expected,
--- a/test/jdk/java/util/concurrent/atomic/LongAdderDemo.java	Mon Feb 25 18:27:59 2019 +0000
+++ b/test/jdk/java/util/concurrent/atomic/LongAdderDemo.java	Wed May 22 22:06:28 2019 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, 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
@@ -46,6 +46,7 @@
 import java.util.concurrent.Phaser;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.LongAdder;
+import java.util.concurrent.atomic.LongAdderCPU;
 
 public class LongAdderDemo {
     static final int INCS_PER_THREAD = 10000000;
@@ -58,18 +59,33 @@
         boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
         int maxNumThreads = shortRun ? SHORT_RUN_MAX_THREADS : LONG_RUN_MAX_THREADS;
 
+        String base = "AtomicLong";
+        String test = "LongAdder";
+        if (args.length > 2) {
+            base = args[1];
+            test = args[2];
+        } else if (args.length > 1) {
+            test = args[1];
+        }
+
         System.out.println("Warmup...");
         int half = NCPU > 1 ? NCPU / 2 : 1;
-        if (!shortRun)
+        if (!shortRun && base.equals("AtomicLong") || test.equals("AtomicLong"))
             casTest(half, 1000);
-        adderTest(half, 1000);
+        if (base.equals("LongAdder") || test.equals("LongAdder"))
+            adderTest(half, 1000);
+        if (base.equals("LongAdderCPU") || test.equals("LongAdderCPU"))
+            adderTestCPU(half, 1000);
 
         for (int reps = 0; reps < 2; ++reps) {
             System.out.println("Running...");
             for (int i = 1; i <= maxNumThreads; i <<= 1) {
-                if (!shortRun)
+                if (!shortRun && (base.equals("AtomicLong") || test.equals("AtomicLong")))
                     casTest(i, INCS_PER_THREAD);
-                adderTest(i, INCS_PER_THREAD);
+                if (base.equals("LongAdder") || test.equals("LongAdder"))
+                    adderTest(i, INCS_PER_THREAD);
+                if (base.equals("LongAdderCPU") || test.equals("LongAdderCPU"))
+                    adderTestCPU(i, INCS_PER_THREAD);
             }
         }
         pool.shutdown();
@@ -85,7 +101,7 @@
     }
 
     static void adderTest(int nthreads, int incs) {
-        System.out.print("LongAdder  ");
+        System.out.print("LongAdder    ");
         Phaser phaser = new Phaser(nthreads + 1);
         LongAdder a = new LongAdder();
         for (int i = 0; i < nthreads; ++i)
@@ -93,6 +109,15 @@
         report(nthreads, incs, timeTasks(phaser), a.sum());
     }
 
+    static void adderTestCPU(int nthreads, int incs) {
+        System.out.print("LongAdderCPU ");
+        Phaser phaser = new Phaser(nthreads + 1);
+        LongAdderCPU a = new LongAdderCPU();
+        for (int i = 0; i < nthreads; ++i)
+            pool.execute(new AdderTaskCPU(a, phaser, incs));
+        report(nthreads, incs, timeTasks(phaser), a.sum());
+    }
+
     static void report(int nthreads, int incs, long elapsedNanos, long sum) {
         long total = (long)nthreads * incs;
         if (sum != total)
@@ -133,6 +158,28 @@
         }
     }
 
+    static final class AdderTaskCPU implements Runnable {
+        final LongAdderCPU adder;
+        final Phaser phaser;
+        final int incs;
+        volatile long result;
+        AdderTaskCPU(LongAdderCPU adder, Phaser phaser, int incs) {
+            this.adder = adder;
+            this.phaser = phaser;
+            this.incs = incs;
+        }
+
+        public void run() {
+            phaser.arriveAndAwaitAdvance();
+            phaser.arriveAndAwaitAdvance();
+            LongAdderCPU a = adder;
+            for (int i = 0; i < incs; ++i)
+                a.increment();
+            result = a.sum();
+            phaser.arrive();
+        }
+    }
+
     static final class CasTask implements Runnable {
         final AtomicLong adder;
         final Phaser phaser;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/micro/org/openjdk/bench/java/util/concurrent/LongAdderAdd.java	Wed May 22 22:06:28 2019 -0400
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+package org.openjdk.bench.java.util.concurrent;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Threads;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.LongAdder;
+import java.util.concurrent.atomic.LongAdderCPU;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * Benchmark vanilla LongAdder vs LongAdder with Unsafe.compareAndSetLongCPU support.
+ * Benchmark vanilla compareAndSet vs compareAndSetLongCPU.
+ *
+ */
+@BenchmarkMode({Mode.Throughput})
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Threads(Threads.MAX)
+@State(Scope.Benchmark)
+public class LongAdderAdd {
+
+    private LongAdder count0;
+    private LongAdderCPU count1;
+
+    @Setup
+    public void setup() {
+        count0 = new LongAdder();
+        count1 = new LongAdderCPU();
+    }
+
+    @Benchmark
+    public void testAddBaseline() {
+        count0.add(1);
+    }
+
+    @Benchmark
+    public void testAddCPU() {
+        count1.add(1);
+    }
+
+    @State(Scope.Thread)
+    public static class ThreadState {
+        volatile long value = 0L;
+    }
+
+    private static final Unsafe U = Unsafe.getUnsafe();
+    private static final VarHandle VALUE;
+    private static final long offset;
+
+    static {
+	try {
+	    MethodHandles.Lookup l = MethodHandles.lookup();
+	    VALUE = l.findVarHandle(ThreadState.class, "value", long.class);
+	    offset = U.objectFieldOffset(ThreadState.class, "value");
+	} catch (ReflectiveOperationException e) {
+	    throw new ExceptionInInitializerError(e);
+	}
+    }
+
+    @Benchmark
+    public void testCAS(ThreadState s) {
+        VALUE.compareAndSet(s, 0L, 0L);
+    }
+
+    @Benchmark
+    public void testCASCPU(ThreadState s) {
+	int cpu = U.getProcessorId();
+        U.compareAndSetLongCPU(s, offset, cpu, 0L, 0L);
+    }
+
+}