changeset 52878:3d499d469f62 processorid

Processor ID
author rbackman
date Thu, 06 Dec 2018 12:18:29 +0100
parents 732bec44c89e
children 218799944c24
files microbenchmarks/loom/Pid.java src/hotspot/cpu/x86/assembler_x86.cpp src/hotspot/cpu/x86/assembler_x86.hpp src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp src/hotspot/cpu/x86/vm_version_x86.hpp src/hotspot/cpu/x86/x86_64.ad src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp src/hotspot/os_cpu/linux_x86/os_linux_x86.hpp 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/classfile/vmSymbols.hpp src/hotspot/share/opto/c2compiler.cpp src/hotspot/share/opto/classes.hpp src/hotspot/share/opto/intrinsicnode.hpp src/hotspot/share/opto/library_call.cpp src/hotspot/share/opto/node.hpp src/hotspot/share/prims/unsafe.cpp src/java.base/share/classes/jdk/internal/misc/Unsafe.java
diffstat 25 files changed, 416 insertions(+), 207 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/microbenchmarks/loom/Pid.java	Thu Dec 06 12:18:29 2018 +0100
@@ -0,0 +1,39 @@
+import jdk.internal.misc.Unsafe;
+
+public class Pid {
+  public static void main(String[] args) throws Exception {
+    for (int i = 0; i < 32; ++i) {
+      new Thread(() -> {
+        loop2();
+      }).start();
+    }
+    loop2();
+  }
+
+  public static void loop2() {
+    Unsafe u = Unsafe.getUnsafe();
+    int old = u.getProcessorId();
+    while (true) {
+      int n = u.getProcessorId();
+      if (old != n) {
+        System.out.println("Changed " + old + " -> " + n);
+        old = n;
+      }
+    }
+  }
+
+  public static void loop() {
+    Unsafe u = Unsafe.getUnsafe();
+    try {
+      while (true) {
+        run(u);
+        Thread.sleep(100);
+      }
+    } catch (Exception e) {
+    }
+  }
+
+  public static void run(Unsafe u) {
+    System.out.println(Thread.currentThread() + " " + u.getProcessorId());
+  }
+}
--- a/src/hotspot/cpu/x86/assembler_x86.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -4334,6 +4334,23 @@
   emit_int8((unsigned char)0x31);
 }
 
+void Assembler::rdtscp() {
+  emit_int8((unsigned char)0x0F);
+  emit_int8((unsigned char)0x01);
+  emit_int8((unsigned char)0xF9);
+}
+
+void Assembler::rdpid(Register dst) {
+  assert(VM_Version::supports_rdpid(), "");
+  int encode = prefix_and_encode(dst->encoding());
+
+  emit_int8((unsigned char)0xF3);
+  emit_int8((unsigned char)0x0F);
+  emit_int8((unsigned char)0xC7);
+
+  emit_int8((unsigned char)(0xC0 | 7 << 3 | encode));
+}
+
 // copies data from [esi] to [edi] using rcx pointer sized words
 // generic
 void Assembler::rep_mov() {
@@ -9181,4 +9198,5 @@
   emit_operand(dst, src);
 }
 
+
 #endif // !LP64
--- a/src/hotspot/cpu/x86/assembler_x86.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/cpu/x86/assembler_x86.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -1752,6 +1752,8 @@
   void rcpss(XMMRegister dst, XMMRegister src);
 
   void rdtsc();
+  void rdtscp();
+  void rdpid(Register dst);
 
   void ret(int imm16);
 
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -4014,4 +4014,19 @@
   }
 }
 
+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, "");
+  }
+}
+
 #undef __
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -62,4 +62,8 @@
   void store_parameter(jobject c,   int offset_from_esp_in_words);
   void store_parameter(Metadata* c, int offset_from_esp_in_words);
 
+
+  void rdtscp(LIR_Opr dst, LIR_Opr tmp, LIR_Opr tmp1);
+  void rdpic(LIR_Opr dst);
+
 #endif // CPU_X86_VM_C1_LIRASSEMBLER_X86_HPP
--- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -339,7 +339,6 @@
   set_result(x, round_item(reg));
 }
 
-
 // for  _fadd, _fmul, _fsub, _fdiv, _frem
 //      _dadd, _dmul, _dsub, _ddiv, _drem
 void LIRGenerator::do_ArithmeticOp_FPU(ArithmeticOp* x) {
@@ -1516,3 +1515,19 @@
     __ load(address, result, info);
   }
 }
+
+void LIRGenerator::do_getProcessorId(Intrinsic* x) {
+  LIR_Opr result = rlock_result(x);
+  if (VM_Version::supports_rdpid()) {
+    __ getprocessorid(result, LIR_OprFact::illegalOpr, LIR_OprFact::illegalOpr);
+  } else if (VM_Version::supports_rdtscp()) {
+    LIR_Opr result_reg = FrameMap::rcx_opr;
+    LIR_Opr tmp = FrameMap::rdx_opr; 
+    LIR_Opr tmp1 = FrameMap::rax_opr; 
+    __ getprocessorid(result_reg, tmp, tmp1);
+    __ move(result_reg, result);
+  } else {
+    assert(false, "");
+  }
+}
+
--- a/src/hotspot/cpu/x86/vm_version_x86.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/cpu/x86/vm_version_x86.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -162,7 +162,9 @@
                mmx_amd   : 1,
                mmx       : 1,
                fxsr      : 1,
-                         : 4,
+                         : 2,
+               rdtscp    : 1,
+                         : 1,
                long_mode : 1,
                tdnow2    : 1,
                tdnow     : 1;
@@ -246,7 +248,9 @@
              avx512_bitalg : 1,
                            : 1,
           avx512_vpopcntdq : 1,
-                           : 17;
+                           : 7,
+                     rdpid : 1,
+                           : 9;
     } bits;
   };
 
@@ -324,7 +328,7 @@
     CPU_AVX512DQ = (1 << 27),
     CPU_AVX512PF = (1 << 28),
     CPU_AVX512ER = (1 << 29),
-    CPU_AVX512CD = (1 << 30)
+    CPU_AVX512CD = (1 << 30),
     // Keeping sign bit 31 unassigned.
   };
 
@@ -336,6 +340,8 @@
 #define CPU_AVX512_VPOPCNTDQ ((uint64_t)UCONST64(0x2000000000)) // Vector popcount
 #define CPU_VPCLMULQDQ ((uint64_t)UCONST64(0x4000000000)) //Vector carryless multiplication
 #define CPU_VAES ((uint64_t)UCONST64(0x8000000000))    // Vector AES instructions
+#define CPU_RDTSCP ((uint64_t)UCONST64(0x10000000000))
+#define CPU_RDPID ((uint64_t)UCONST64(0x20000000000))
 
   enum Extended_Family {
     // AMD
@@ -572,6 +578,10 @@
       result |= CPU_SHA;
     if (_cpuid_info.std_cpuid1_ecx.bits.fma != 0)
       result |= CPU_FMA;
+    if (_cpuid_info.ext_cpuid1_edx.bits.rdtscp != 0)
+      result |= CPU_RDTSCP;
+    if (_cpuid_info.sef_cpuid7_ecx.bits.rdpid != 0)
+      result |= CPU_RDPID;
 
     // AMD features.
     if (is_amd()) {
@@ -828,6 +838,8 @@
   static bool supports_vpopcntdq()  { return (_features & CPU_AVX512_VPOPCNTDQ) != 0; }
   static bool supports_vpclmulqdq() { return (_features & CPU_VPCLMULQDQ) != 0; }
   static bool supports_vaes()       { return (_features & CPU_VAES) != 0; }
+  static bool supports_rdtscp()     { return (_features & CPU_RDTSCP) != 0; }
+  static bool supports_rdpid()      { return (_features & CPU_RDPID) != 0; }
 
   // Intel features
   static bool is_intel_family_core() { return is_intel() &&
--- a/src/hotspot/cpu/x86/x86_64.ad	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/cpu/x86/x86_64.ad	Thu Dec 06 12:18:29 2018 +0100
@@ -11312,6 +11312,34 @@
   ins_pipe( pipe_slow );
 %}
 
+instruct rdpidProcessorId(rRegI dst, rFlagsReg cr) %{
+  predicate(VM_Version::supports_rdpid());
+  match(Set dst (GetProcessorId));
+  effect(DEF dst, KILL cr);
+  ins_cost(10);
+
+  ins_encode %{
+    Register Rdst = $dst$$Register;
+    __ rdpid(Rdst);
+    __ andl(Rdst, 0xfff); // this is linux specific
+  %}
+  ins_pipe( pipe_slow );
+%}
+
+instruct rdtscpProcessorId(rcx_RegI dst, rdx_RegI tmp, rax_RegI tmp1, rFlagsReg cr) %{
+  predicate(VM_Version::supports_rdtscp());
+  match(Set dst (GetProcessorId));
+  effect(DEF dst, TEMP tmp, TEMP tmp1, KILL cr);
+  ins_cost(100);
+
+  ins_encode %{
+    Register Rdst = $dst$$Register;
+    __ rdtscp();
+    __ andl(Rdst, 0xfff); // this is linux specific
+  %}
+  ins_pipe( pipe_slow );
+%}
+
 //----------Overflow Math Instructions-----------------------------------------
 
 instruct overflowAddI_rReg(rFlagsReg cr, rax_RegI op1, rRegI op2)
--- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -75,6 +75,7 @@
 # include <pwd.h>
 # include <poll.h>
 # include <ucontext.h>
+# include <cpuid.h>
 #ifndef AMD64
 # include <fpu_control.h>
 #endif
@@ -900,3 +901,9 @@
   // JDK-8050147 requires the full cache line bang for x86.
   return VM_Version::L1_line_size();
 }
+
+int os::getProcessorId() {
+  unsigned int eax, ebx, ecx, edx;
+  __cpuid(0xb, eax, ebx, ecx, edx);
+  return edx;
+}
--- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -49,4 +49,6 @@
    */
   static void workaround_expand_exec_shield_cs_limit();
 
+  static int getProcessorId();
+
 #endif // OS_CPU_LINUX_X86_VM_OS_LINUX_X86_HPP
--- a/src/hotspot/share/c1/c1_Compiler.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/c1/c1_Compiler.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -225,6 +225,7 @@
   case vmIntrinsics::_getEventWriter:
 #if defined(_LP64) || !defined(TRACE_ID_SHIFT)
   case vmIntrinsics::_getClassId:
+  case vmIntrinsics::_getProcessorId:
 #endif
 #endif
     break;
--- a/src/hotspot/share/c1/c1_LIR.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/c1/c1_LIR.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -679,6 +679,15 @@
       break;
     }
 
+    case lir_getprocessorid: {
+      LIR_Op2* op2 = (LIR_Op2*)op;
+      assert(op2->_result->is_valid(), "must be"); do_output(op2->_result);
+      if (op2->_opr1->is_valid()) do_temp(op2->_opr1);
+      if (op2->_opr2->is_valid()) do_temp(op2->_opr2);
+      break;
+    }
+
+
 // LIR_Op3
     case lir_idiv:
     case lir_irem: {
@@ -1705,6 +1714,7 @@
      case lir_irem:                  s = "irem";          break;
      case lir_fmad:                  s = "fmad";          break;
      case lir_fmaf:                  s = "fmaf";          break;
+     case lir_getprocessorid:        s = "getprocesssorid"; break;
      // LIR_OpJavaCall
      case lir_static_call:           s = "static";        break;
      case lir_optvirtual_call:       s = "optvirtual";    break;
--- a/src/hotspot/share/c1/c1_LIR.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/c1/c1_LIR.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -31,249 +31,249 @@
 #include "utilities/globalDefinitions.hpp"
 
 class BlockBegin;
-class BlockList;
-class LIR_Assembler;
-class CodeEmitInfo;
-class CodeStub;
-class CodeStubList;
-class ArrayCopyStub;
-class LIR_Op;
-class ciType;
-class ValueType;
-class LIR_OpVisitState;
-class FpuStackSim;
+  class BlockList;
+  class LIR_Assembler;
+  class CodeEmitInfo;
+  class CodeStub;
+  class CodeStubList;
+  class ArrayCopyStub;
+  class LIR_Op;
+  class ciType;
+  class ValueType;
+  class LIR_OpVisitState;
+  class FpuStackSim;
 
-//---------------------------------------------------------------------
-//                 LIR Operands
-//  LIR_OprDesc
-//    LIR_OprPtr
-//      LIR_Const
-//      LIR_Address
-//---------------------------------------------------------------------
-class LIR_OprDesc;
-class LIR_OprPtr;
-class LIR_Const;
-class LIR_Address;
-class LIR_OprVisitor;
+  //---------------------------------------------------------------------
+  //                 LIR Operands
+  //  LIR_OprDesc
+  //    LIR_OprPtr
+  //      LIR_Const
+  //      LIR_Address
+  //---------------------------------------------------------------------
+  class LIR_OprDesc;
+  class LIR_OprPtr;
+  class LIR_Const;
+  class LIR_Address;
+  class LIR_OprVisitor;
 
 
-typedef LIR_OprDesc* LIR_Opr;
-typedef int          RegNr;
+  typedef LIR_OprDesc* LIR_Opr;
+  typedef int          RegNr;
 
-typedef GrowableArray<LIR_Opr> LIR_OprList;
-typedef GrowableArray<LIR_Op*> LIR_OpArray;
-typedef GrowableArray<LIR_Op*> LIR_OpList;
+  typedef GrowableArray<LIR_Opr> LIR_OprList;
+  typedef GrowableArray<LIR_Op*> LIR_OpArray;
+  typedef GrowableArray<LIR_Op*> LIR_OpList;
 
-// define LIR_OprPtr early so LIR_OprDesc can refer to it
-class LIR_OprPtr: public CompilationResourceObj {
- public:
-  bool is_oop_pointer() const                    { return (type() == T_OBJECT); }
-  bool is_float_kind() const                     { BasicType t = type(); return (t == T_FLOAT) || (t == T_DOUBLE); }
+  // define LIR_OprPtr early so LIR_OprDesc can refer to it
+  class LIR_OprPtr: public CompilationResourceObj {
+   public:
+    bool is_oop_pointer() const                    { return (type() == T_OBJECT); }
+    bool is_float_kind() const                     { BasicType t = type(); return (t == T_FLOAT) || (t == T_DOUBLE); }
 
-  virtual LIR_Const*  as_constant()              { return NULL; }
-  virtual LIR_Address* as_address()              { return NULL; }
-  virtual BasicType type() const                 = 0;
-  virtual void print_value_on(outputStream* out) const = 0;
-};
+    virtual LIR_Const*  as_constant()              { return NULL; }
+    virtual LIR_Address* as_address()              { return NULL; }
+    virtual BasicType type() const                 = 0;
+    virtual void print_value_on(outputStream* out) const = 0;
+  };
 
 
 
-// LIR constants
-class LIR_Const: public LIR_OprPtr {
- private:
-  JavaValue _value;
+  // LIR constants
+  class LIR_Const: public LIR_OprPtr {
+   private:
+    JavaValue _value;
 
-  void type_check(BasicType t) const   { assert(type() == t, "type check"); }
-  void type_check(BasicType t1, BasicType t2) const   { assert(type() == t1 || type() == t2, "type check"); }
-  void type_check(BasicType t1, BasicType t2, BasicType t3) const   { assert(type() == t1 || type() == t2 || type() == t3, "type check"); }
+    void type_check(BasicType t) const   { assert(type() == t, "type check"); }
+    void type_check(BasicType t1, BasicType t2) const   { assert(type() == t1 || type() == t2, "type check"); }
+    void type_check(BasicType t1, BasicType t2, BasicType t3) const   { assert(type() == t1 || type() == t2 || type() == t3, "type check"); }
 
- public:
-  LIR_Const(jint i, bool is_address=false)       { _value.set_type(is_address?T_ADDRESS:T_INT); _value.set_jint(i); }
-  LIR_Const(jlong l)                             { _value.set_type(T_LONG);    _value.set_jlong(l); }
-  LIR_Const(jfloat f)                            { _value.set_type(T_FLOAT);   _value.set_jfloat(f); }
-  LIR_Const(jdouble d)                           { _value.set_type(T_DOUBLE);  _value.set_jdouble(d); }
-  LIR_Const(jobject o)                           { _value.set_type(T_OBJECT);  _value.set_jobject(o); }
-  LIR_Const(void* p) {
+   public:
+    LIR_Const(jint i, bool is_address=false)       { _value.set_type(is_address?T_ADDRESS:T_INT); _value.set_jint(i); }
+    LIR_Const(jlong l)                             { _value.set_type(T_LONG);    _value.set_jlong(l); }
+    LIR_Const(jfloat f)                            { _value.set_type(T_FLOAT);   _value.set_jfloat(f); }
+    LIR_Const(jdouble d)                           { _value.set_type(T_DOUBLE);  _value.set_jdouble(d); }
+    LIR_Const(jobject o)                           { _value.set_type(T_OBJECT);  _value.set_jobject(o); }
+    LIR_Const(void* p) {
 #ifdef _LP64
-    assert(sizeof(jlong) >= sizeof(p), "too small");;
-    _value.set_type(T_LONG);    _value.set_jlong((jlong)p);
+      assert(sizeof(jlong) >= sizeof(p), "too small");;
+      _value.set_type(T_LONG);    _value.set_jlong((jlong)p);
 #else
-    assert(sizeof(jint) >= sizeof(p), "too small");;
-    _value.set_type(T_INT);     _value.set_jint((jint)p);
+      assert(sizeof(jint) >= sizeof(p), "too small");;
+      _value.set_type(T_INT);     _value.set_jint((jint)p);
 #endif
-  }
-  LIR_Const(Metadata* m) {
-    _value.set_type(T_METADATA);
+    }
+    LIR_Const(Metadata* m) {
+      _value.set_type(T_METADATA);
 #ifdef _LP64
-    _value.set_jlong((jlong)m);
+      _value.set_jlong((jlong)m);
 #else
-    _value.set_jint((jint)m);
+      _value.set_jint((jint)m);
 #endif // _LP64
-  }
+    }
 
-  virtual BasicType type()       const { return _value.get_type(); }
-  virtual LIR_Const* as_constant()     { return this; }
+    virtual BasicType type()       const { return _value.get_type(); }
+    virtual LIR_Const* as_constant()     { return this; }
 
-  jint      as_jint()    const         { type_check(T_INT, T_ADDRESS); return _value.get_jint(); }
-  jlong     as_jlong()   const         { type_check(T_LONG  ); return _value.get_jlong(); }
-  jfloat    as_jfloat()  const         { type_check(T_FLOAT ); return _value.get_jfloat(); }
-  jdouble   as_jdouble() const         { type_check(T_DOUBLE); return _value.get_jdouble(); }
-  jobject   as_jobject() const         { type_check(T_OBJECT); return _value.get_jobject(); }
-  jint      as_jint_lo() const         { type_check(T_LONG  ); return low(_value.get_jlong()); }
-  jint      as_jint_hi() const         { type_check(T_LONG  ); return high(_value.get_jlong()); }
+    jint      as_jint()    const         { type_check(T_INT, T_ADDRESS); return _value.get_jint(); }
+    jlong     as_jlong()   const         { type_check(T_LONG  ); return _value.get_jlong(); }
+    jfloat    as_jfloat()  const         { type_check(T_FLOAT ); return _value.get_jfloat(); }
+    jdouble   as_jdouble() const         { type_check(T_DOUBLE); return _value.get_jdouble(); }
+    jobject   as_jobject() const         { type_check(T_OBJECT); return _value.get_jobject(); }
+    jint      as_jint_lo() const         { type_check(T_LONG  ); return low(_value.get_jlong()); }
+    jint      as_jint_hi() const         { type_check(T_LONG  ); return high(_value.get_jlong()); }
 
 #ifdef _LP64
-  address   as_pointer() const         { type_check(T_LONG  ); return (address)_value.get_jlong(); }
-  Metadata* as_metadata() const        { type_check(T_METADATA); return (Metadata*)_value.get_jlong(); }
+    address   as_pointer() const         { type_check(T_LONG  ); return (address)_value.get_jlong(); }
+    Metadata* as_metadata() const        { type_check(T_METADATA); return (Metadata*)_value.get_jlong(); }
 #else
-  address   as_pointer() const         { type_check(T_INT   ); return (address)_value.get_jint(); }
-  Metadata* as_metadata() const        { type_check(T_METADATA); return (Metadata*)_value.get_jint(); }
+    address   as_pointer() const         { type_check(T_INT   ); return (address)_value.get_jint(); }
+    Metadata* as_metadata() const        { type_check(T_METADATA); return (Metadata*)_value.get_jint(); }
 #endif
 
 
-  jint      as_jint_bits() const       { type_check(T_FLOAT, T_INT, T_ADDRESS); return _value.get_jint(); }
-  jint      as_jint_lo_bits() const    {
-    if (type() == T_DOUBLE) {
-      return low(jlong_cast(_value.get_jdouble()));
-    } else {
-      return as_jint_lo();
+    jint      as_jint_bits() const       { type_check(T_FLOAT, T_INT, T_ADDRESS); return _value.get_jint(); }
+    jint      as_jint_lo_bits() const    {
+      if (type() == T_DOUBLE) {
+        return low(jlong_cast(_value.get_jdouble()));
+      } else {
+        return as_jint_lo();
+      }
     }
-  }
-  jint      as_jint_hi_bits() const    {
-    if (type() == T_DOUBLE) {
-      return high(jlong_cast(_value.get_jdouble()));
-    } else {
-      return as_jint_hi();
+    jint      as_jint_hi_bits() const    {
+      if (type() == T_DOUBLE) {
+        return high(jlong_cast(_value.get_jdouble()));
+      } else {
+        return as_jint_hi();
+      }
     }
-  }
-  jlong      as_jlong_bits() const    {
-    if (type() == T_DOUBLE) {
-      return jlong_cast(_value.get_jdouble());
-    } else {
-      return as_jlong();
+    jlong      as_jlong_bits() const    {
+      if (type() == T_DOUBLE) {
+        return jlong_cast(_value.get_jdouble());
+      } else {
+        return as_jlong();
+      }
     }
-  }
 
-  virtual void print_value_on(outputStream* out) const PRODUCT_RETURN;
+    virtual void print_value_on(outputStream* out) const PRODUCT_RETURN;
 
 
-  bool is_zero_float() {
-    jfloat f = as_jfloat();
-    jfloat ok = 0.0f;
-    return jint_cast(f) == jint_cast(ok);
-  }
+    bool is_zero_float() {
+      jfloat f = as_jfloat();
+      jfloat ok = 0.0f;
+      return jint_cast(f) == jint_cast(ok);
+    }
 
-  bool is_one_float() {
-    jfloat f = as_jfloat();
-    return !g_isnan(f) && g_isfinite(f) && f == 1.0;
-  }
+    bool is_one_float() {
+      jfloat f = as_jfloat();
+      return !g_isnan(f) && g_isfinite(f) && f == 1.0;
+    }
 
-  bool is_zero_double() {
-    jdouble d = as_jdouble();
-    jdouble ok = 0.0;
-    return jlong_cast(d) == jlong_cast(ok);
-  }
+    bool is_zero_double() {
+      jdouble d = as_jdouble();
+      jdouble ok = 0.0;
+      return jlong_cast(d) == jlong_cast(ok);
+    }
 
-  bool is_one_double() {
-    jdouble d = as_jdouble();
-    return !g_isnan(d) && g_isfinite(d) && d == 1.0;
-  }
-};
-
-
-//---------------------LIR Operand descriptor------------------------------------
-//
-// The class LIR_OprDesc represents a LIR instruction operand;
-// it can be a register (ALU/FPU), stack location or a constant;
-// Constants and addresses are represented as resource area allocated
-// structures (see above).
-// Registers and stack locations are inlined into the this pointer
-// (see value function).
-
-class LIR_OprDesc: public CompilationResourceObj {
- public:
-  // value structure:
-  //     data       opr-type opr-kind
-  // +--------------+-------+-------+
-  // [max...........|7 6 5 4|3 2 1 0]
-  //                               ^
-  //                         is_pointer bit
-  //
-  // lowest bit cleared, means it is a structure pointer
-  // we need  4 bits to represent types
-
- private:
-  friend class LIR_OprFact;
-
-  // Conversion
-  intptr_t value() const                         { return (intptr_t) this; }
-
-  bool check_value_mask(intptr_t mask, intptr_t masked_value) const {
-    return (value() & mask) == masked_value;
-  }
-
-  enum OprKind {
-      pointer_value      = 0
-    , stack_value        = 1
-    , cpu_register       = 3
-    , fpu_register       = 5
-    , illegal_value      = 7
+    bool is_one_double() {
+      jdouble d = as_jdouble();
+      return !g_isnan(d) && g_isfinite(d) && d == 1.0;
+    }
   };
 
-  enum OprBits {
-      pointer_bits   = 1
-    , kind_bits      = 3
-    , type_bits      = 4
-    , size_bits      = 2
-    , destroys_bits  = 1
-    , virtual_bits   = 1
-    , is_xmm_bits    = 1
-    , last_use_bits  = 1
-    , is_fpu_stack_offset_bits = 1        // used in assertion checking on x86 for FPU stack slot allocation
-    , non_data_bits  = kind_bits + type_bits + size_bits + destroys_bits + last_use_bits +
-                       is_fpu_stack_offset_bits + virtual_bits + is_xmm_bits
-    , data_bits      = BitsPerInt - non_data_bits
-    , reg_bits       = data_bits / 2      // for two registers in one value encoding
-  };
 
-  enum OprShift {
-      kind_shift     = 0
-    , type_shift     = kind_shift     + kind_bits
-    , size_shift     = type_shift     + type_bits
-    , destroys_shift = size_shift     + size_bits
-    , last_use_shift = destroys_shift + destroys_bits
-    , is_fpu_stack_offset_shift = last_use_shift + last_use_bits
-    , virtual_shift  = is_fpu_stack_offset_shift + is_fpu_stack_offset_bits
-    , is_xmm_shift   = virtual_shift + virtual_bits
-    , data_shift     = is_xmm_shift + is_xmm_bits
-    , reg1_shift = data_shift
-    , reg2_shift = data_shift + reg_bits
+  //---------------------LIR Operand descriptor------------------------------------
+  //
+  // The class LIR_OprDesc represents a LIR instruction operand;
+  // it can be a register (ALU/FPU), stack location or a constant;
+  // Constants and addresses are represented as resource area allocated
+  // structures (see above).
+  // Registers and stack locations are inlined into the this pointer
+  // (see value function).
 
-  };
+  class LIR_OprDesc: public CompilationResourceObj {
+   public:
+    // value structure:
+    //     data       opr-type opr-kind
+    // +--------------+-------+-------+
+    // [max...........|7 6 5 4|3 2 1 0]
+    //                               ^
+    //                         is_pointer bit
+    //
+    // lowest bit cleared, means it is a structure pointer
+    // we need  4 bits to represent types
 
-  enum OprSize {
-      single_size = 0 << size_shift
-    , double_size = 1 << size_shift
-  };
+   private:
+    friend class LIR_OprFact;
 
-  enum OprMask {
-      kind_mask      = right_n_bits(kind_bits)
-    , type_mask      = right_n_bits(type_bits) << type_shift
-    , size_mask      = right_n_bits(size_bits) << size_shift
-    , last_use_mask  = right_n_bits(last_use_bits) << last_use_shift
-    , is_fpu_stack_offset_mask = right_n_bits(is_fpu_stack_offset_bits) << is_fpu_stack_offset_shift
-    , virtual_mask   = right_n_bits(virtual_bits) << virtual_shift
-    , is_xmm_mask    = right_n_bits(is_xmm_bits) << is_xmm_shift
-    , pointer_mask   = right_n_bits(pointer_bits)
-    , lower_reg_mask = right_n_bits(reg_bits)
-    , no_type_mask   = (int)(~(type_mask | last_use_mask | is_fpu_stack_offset_mask))
-  };
+    // Conversion
+    intptr_t value() const                         { return (intptr_t) this; }
 
-  uintptr_t data() const                         { return value() >> data_shift; }
-  int lo_reg_half() const                        { return data() & lower_reg_mask; }
-  int hi_reg_half() const                        { return (data() >> reg_bits) & lower_reg_mask; }
-  OprKind kind_field() const                     { return (OprKind)(value() & kind_mask); }
-  OprSize size_field() const                     { return (OprSize)(value() & size_mask); }
+    bool check_value_mask(intptr_t mask, intptr_t masked_value) const {
+      return (value() & mask) == masked_value;
+    }
+
+    enum OprKind {
+        pointer_value      = 0
+      , stack_value        = 1
+      , cpu_register       = 3
+      , fpu_register       = 5
+      , illegal_value      = 7
+    };
+
+    enum OprBits {
+        pointer_bits   = 1
+      , kind_bits      = 3
+      , type_bits      = 4
+      , size_bits      = 2
+      , destroys_bits  = 1
+      , virtual_bits   = 1
+      , is_xmm_bits    = 1
+      , last_use_bits  = 1
+      , is_fpu_stack_offset_bits = 1        // used in assertion checking on x86 for FPU stack slot allocation
+      , non_data_bits  = kind_bits + type_bits + size_bits + destroys_bits + last_use_bits +
+                         is_fpu_stack_offset_bits + virtual_bits + is_xmm_bits
+      , data_bits      = BitsPerInt - non_data_bits
+      , reg_bits       = data_bits / 2      // for two registers in one value encoding
+    };
+
+    enum OprShift {
+        kind_shift     = 0
+      , type_shift     = kind_shift     + kind_bits
+      , size_shift     = type_shift     + type_bits
+      , destroys_shift = size_shift     + size_bits
+      , last_use_shift = destroys_shift + destroys_bits
+      , is_fpu_stack_offset_shift = last_use_shift + last_use_bits
+      , virtual_shift  = is_fpu_stack_offset_shift + is_fpu_stack_offset_bits
+      , is_xmm_shift   = virtual_shift + virtual_bits
+      , data_shift     = is_xmm_shift + is_xmm_bits
+      , reg1_shift = data_shift
+      , reg2_shift = data_shift + reg_bits
+
+    };
+
+    enum OprSize {
+        single_size = 0 << size_shift
+      , double_size = 1 << size_shift
+    };
+
+    enum OprMask {
+        kind_mask      = right_n_bits(kind_bits)
+      , type_mask      = right_n_bits(type_bits) << type_shift
+      , size_mask      = right_n_bits(size_bits) << size_shift
+      , last_use_mask  = right_n_bits(last_use_bits) << last_use_shift
+      , is_fpu_stack_offset_mask = right_n_bits(is_fpu_stack_offset_bits) << is_fpu_stack_offset_shift
+      , virtual_mask   = right_n_bits(virtual_bits) << virtual_shift
+      , is_xmm_mask    = right_n_bits(is_xmm_bits) << is_xmm_shift
+      , pointer_mask   = right_n_bits(pointer_bits)
+      , lower_reg_mask = right_n_bits(reg_bits)
+      , no_type_mask   = (int)(~(type_mask | last_use_mask | is_fpu_stack_offset_mask))
+    };
+
+    uintptr_t data() const                         { return value() >> data_shift; }
+    int lo_reg_half() const                        { return data() & lower_reg_mask; }
+    int hi_reg_half() const                        { return (data() >> reg_bits) & lower_reg_mask; }
+    OprKind kind_field() const                     { return (OprKind)(value() & kind_mask); }
+    OprSize size_field() const                     { return (OprSize)(value() & size_mask); }
 
   static char type_char(BasicType t);
 
@@ -952,6 +952,7 @@
       , lir_compare_to
       , lir_xadd
       , lir_xchg
+      , lir_getprocessorid
   , end_op2
   , begin_op3
       , lir_idiv
@@ -2136,6 +2137,8 @@
   void push(LIR_Opr opr)                                   { append(new LIR_Op1(lir_push, opr)); }
   void pop(LIR_Opr reg)                                    { append(new LIR_Op1(lir_pop,  reg)); }
 
+  void getprocessorid(LIR_Opr dst, LIR_Opr tmp1, LIR_Opr tmp2) { append(new LIR_Op2(lir_getprocessorid, tmp1, tmp2, dst)); }
+
   void cmp(LIR_Condition condition, LIR_Opr left, LIR_Opr right, CodeEmitInfo* info = NULL) {
     append(new LIR_Op2(lir_cmp, condition, left, right, info));
   }
--- a/src/hotspot/share/c1/c1_LIRAssembler.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/c1/c1_LIRAssembler.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -767,6 +767,10 @@
       atomic_op(op->code(), op->in_opr1(), op->in_opr2(), op->result_opr(), op->tmp1_opr());
       break;
 
+    case lir_getprocessorid:
+      getprocessorid(op->result_opr(), op->in_opr1(), op->in_opr2());
+      break;
+
     default:
       Unimplemented();
       break;
--- a/src/hotspot/share/c1/c1_LIRAssembler.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/c1/c1_LIRAssembler.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -113,6 +113,8 @@
   void push(LIR_Opr opr);
   void pop(LIR_Opr opr);
 
+  void getprocessorid(LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2);
+
   // 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	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -3098,6 +3098,10 @@
     do_vectorizedMismatch(x);
     break;
 
+  case vmIntrinsics::_getProcessorId:
+    do_getProcessorId(x);
+    break;
+
   default: ShouldNotReachHere(); break;
   }
 }
--- a/src/hotspot/share/c1/c1_LIRGenerator.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -265,6 +265,7 @@
   void do_update_CRC32(Intrinsic* x);
   void do_update_CRC32C(Intrinsic* x);
   void do_vectorizedMismatch(Intrinsic* x);
+  void do_getProcessorId(Intrinsic* x);
 
  public:
   LIR_Opr call_runtime(BasicTypeArray* signature, LIRItemList* args, address entry, ValueType* result_type, CodeEmitInfo* info);
--- a/src/hotspot/share/classfile/vmSymbols.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/classfile/vmSymbols.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -1329,6 +1329,10 @@
   do_intrinsic(_weakCompareAndSetShortAcquire,    jdk_internal_misc_Unsafe,  weakCompareAndSetShortAcquire_name,    compareAndSetShort_signature,       F_R) \
   do_intrinsic(_weakCompareAndSetShortRelease,    jdk_internal_misc_Unsafe,  weakCompareAndSetShortRelease_name,    compareAndSetShort_signature,       F_R) \
   do_intrinsic(_weakCompareAndSetShort,           jdk_internal_misc_Unsafe,  weakCompareAndSetShort_name,           compareAndSetShort_signature,       F_R) \
+  \
+  do_intrinsic(_getProcessorId,           jdk_internal_misc_Unsafe,     getProcessorId_name, getProcessorId_signature, F_RN)   \
+   do_name(     getProcessorId_name,                                    "getProcessorId")                                      \
+   do_alias(    getProcessorId_signature,                               void_int_signature)                                    \
                            \
   do_intrinsic(_getAndAddInt,             jdk_internal_misc_Unsafe,     getAndAddInt_name, getAndAddInt_signature, F_R)       \
    do_name(     getAndAddInt_name,                                      "getAndAddInt")                                       \
--- a/src/hotspot/share/opto/c2compiler.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/opto/c2compiler.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -597,6 +597,7 @@
   case vmIntrinsics::_profileBoolean:
   case vmIntrinsics::_isCompileConstant:
   case vmIntrinsics::_Preconditions_checkIndex:
+  case vmIntrinsics::_getProcessorId:
     break;
   default:
     return false;
--- a/src/hotspot/share/opto/classes.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/opto/classes.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -136,6 +136,7 @@
 macro(ConvL2I)
 macro(CountedLoop)
 macro(CountedLoopEnd)
+macro(GetProcessorId)
 macro(OuterStripMinedLoop)
 macro(OuterStripMinedLoopEnd)
 macro(CountLeadingZerosI)
--- a/src/hotspot/share/opto/intrinsicnode.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/opto/intrinsicnode.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -165,6 +165,17 @@
 };
 
 
+//------------------------------GetProcessorId ---------------------------------
+ class GetProcessorIdNode: public Node {
+  public:
+   GetProcessorIdNode(Node* ctrl):
+     Node(ctrl) {}
+
+   virtual int Opcode() const;
+   virtual uint ideal_reg() const { return Op_RegI; }
+   virtual const Type* bottom_type() const { return TypeInt::INT; }
+ };
+
 //------------------------------EncodeISOArray--------------------------------
 // encode char[] to byte[] in ISO_8859_1
 class EncodeISOArrayNode: public Node {
--- a/src/hotspot/share/opto/library_call.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/opto/library_call.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -327,6 +327,7 @@
 
   bool inline_profileBoolean();
   bool inline_isCompileConstant();
+  bool inline_getProcessorId();
   void clear_upper_avx() {
 #ifdef X86
     if (UseAVX >= 2) {
@@ -867,6 +868,9 @@
   case vmIntrinsics::_fmaF:
     return inline_fma(intrinsic_id());
 
+  case vmIntrinsics::_getProcessorId:
+    return inline_getProcessorId();
+
   default:
     // If you get here, it may be that someone has added a new intrinsic
     // to the list in vmSymbols.hpp without implementing it here.
@@ -6636,3 +6640,12 @@
   set_result(n->is_Con() ? intcon(1) : intcon(0));
   return true;
 }
+
+bool LibraryCallKit::inline_getProcessorId() {
+  if (!Matcher::match_rule_supported(Op_GetProcessorId)) {
+    return false;
+  }
+  set_result(_gvn.transform(new GetProcessorIdNode(control())));
+  return true;
+}
+
--- a/src/hotspot/share/opto/node.hpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/opto/node.hpp	Thu Dec 06 12:18:29 2018 +0100
@@ -716,6 +716,7 @@
     DEFINE_CLASS_ID(Mul,      Node, 12)
     DEFINE_CLASS_ID(Vector,   Node, 13)
     DEFINE_CLASS_ID(ClearArray, Node, 14)
+    DEFINE_CLASS_ID(GetProcessorId, Node, 15)
 
     _max_classes  = ClassMask_ClearArray
   };
--- a/src/hotspot/share/prims/unsafe.cpp	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/hotspot/share/prims/unsafe.cpp	Thu Dec 06 12:18:29 2018 +0100
@@ -302,6 +302,10 @@
   return UseUnalignedAccesses;
 } UNSAFE_END
 
+UNSAFE_LEAF(jint, Unsafe_getProcessorId(JNIEnv *env, jobject unsafe)) {
+  return os::getProcessorId();
+} UNSAFE_END
+
 #define DEFINE_GETSETOOP(java_type, Type) \
  \
 UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \
@@ -1092,7 +1096,8 @@
     {CC "fullFence",          CC "()V",                  FN_PTR(Unsafe_FullFence)},
 
     {CC "isBigEndian0",       CC "()Z",                  FN_PTR(Unsafe_isBigEndian0)},
-    {CC "unalignedAccess0",   CC "()Z",                  FN_PTR(Unsafe_unalignedAccess0)}
+    {CC "unalignedAccess0",   CC "()Z",                  FN_PTR(Unsafe_unalignedAccess0)},
+    {CC "getProcessorId",     CC "()I",                  FN_PTR(Unsafe_getProcessorId)}
 };
 
 #undef CC
--- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Wed Nov 28 10:30:15 2018 -0800
+++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java	Thu Dec 06 12:18:29 2018 +0100
@@ -3595,6 +3595,12 @@
         putCharUnaligned(o, offset, convEndian(bigEndian, x));
     }
 
+    /**
+     * Get the processor id
+     */
+    @HotSpotIntrinsicCandidate
+    public native int getProcessorId();
+
     // JVM interface methods
     // BE is true iff the native endianness of this platform is big.
     private static final boolean BE = theUnsafe.isBigEndian0();