changeset 38017:55047d16f141

8147844: new method j.l.Runtime.onSpinWait() and the corresponding x86 hotspot instrinsic Summary: adds c1 & c2 x86 intrinsics for j.l.Runtime.onSpinWait() that utilize the PAUSE instruction Reviewed-by: iveresov, kvn Contributed-by: Ivan Krylov <ivan@azul.com>, Yuri Gaevsky <ygaevsky@azul.com>
author ikrylov
date Wed, 30 Mar 2016 17:04:14 +0200
parents e00dfcc21fa1
children 1dc6c6f21231
files hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp hotspot/src/cpu/x86/vm/vm_version_x86.hpp hotspot/src/cpu/x86/vm/x86.ad hotspot/src/share/vm/c1/c1_Compiler.cpp hotspot/src/share/vm/c1/c1_LIR.cpp hotspot/src/share/vm/c1/c1_LIR.hpp hotspot/src/share/vm/c1/c1_LIRAssembler.cpp hotspot/src/share/vm/c1/c1_LIRAssembler.hpp hotspot/src/share/vm/c1/c1_LIRGenerator.cpp hotspot/src/share/vm/classfile/vmSymbols.hpp hotspot/src/share/vm/opto/c2compiler.cpp hotspot/src/share/vm/opto/classes.hpp hotspot/src/share/vm/opto/library_call.cpp hotspot/src/share/vm/opto/matcher.cpp hotspot/src/share/vm/opto/memnode.cpp hotspot/src/share/vm/opto/memnode.hpp hotspot/src/share/vm/runtime/vmStructs.cpp hotspot/src/share/vm/runtime/vm_version.hpp hotspot/test/compiler/onSpinWait/TestOnSpinWait.java
diffstat 22 files changed, 172 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -2942,6 +2942,10 @@
 
 void LIR_Assembler::membar_storeload() { __ membar(MacroAssembler::StoreLoad); }
 
+void LIR_Assembler::on_spin_wait() {
+  Unimplemented();
+}
+
 void LIR_Assembler::get_thread(LIR_Opr result_reg) {
   __ mov(result_reg->as_register(), rthread);
 }
--- a/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/cpu/ppc/vm/c1_LIRAssembler_ppc.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -2845,6 +2845,9 @@
   __ membar(Assembler::StoreLoad);
 }
 
+void LIR_Assembler::on_spin_wait() {
+  Unimplemented();
+}
 
 void LIR_Assembler::leal(LIR_Opr addr_opr, LIR_Opr dest) {
   LIR_Address* addr = addr_opr->as_address_ptr();
--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -3313,6 +3313,9 @@
   __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
 }
 
+void LIR_Assembler::on_spin_wait() {
+  Unimplemented();
+}
 
 // Pack two sequential registers containing 32 bit values
 // into a single 64 bit register.
--- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -3886,6 +3886,10 @@
   __ membar(Assembler::Membar_mask_bits(Assembler::StoreLoad));
 }
 
+void LIR_Assembler::on_spin_wait() {
+  __ pause ();
+}
+
 void LIR_Assembler::get_thread(LIR_Opr result_reg) {
   assert(result_reg->is_register(), "check");
 #ifdef _LP64
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.hpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/cpu/x86/vm/vm_version_x86.hpp	Wed Mar 30 17:04:14 2016 +0200
@@ -844,6 +844,11 @@
   static uint32_t get_xsave_header_upper_segment() {
     return _cpuid_info.xem_xcr0_edx;
   }
+
+  // SSE2 and later processors implement a 'pause' instruction
+  // that can be used for efficient implementation of
+  // the intrinsic for java.lang.Thread.onSpinWait()
+  static bool supports_on_spin_wait() { return supports_sse2(); }
 };
 
 #endif // CPU_X86_VM_VM_VERSION_X86_HPP
--- a/hotspot/src/cpu/x86/vm/x86.ad	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/cpu/x86/vm/x86.ad	Wed Mar 30 17:04:14 2016 +0200
@@ -1719,6 +1719,10 @@
       if (!(UseSSE > 4))
         ret_value = false;
       break;
+    case Op_OnSpinWait:
+      if (VM_Version::supports_on_spin_wait() == false)
+        ret_value = false;
+      break;
   }
 
   return ret_value;  // Per default match rules are supported.
@@ -2996,6 +3000,24 @@
   ins_pipe(pipe_slow);
 %}
 
+instruct onspinwait() %{
+  match(OnSpinWait);
+  ins_cost(200);
+
+  format %{
+    $$template
+    if (os::is_MP()) {
+      $$emit$$"pause\t! membar_onspinwait"
+    } else {
+      $$emit$$"MEMBAR-onspinwait ! (empty encoding)"
+    }
+  %}
+  ins_encode %{
+    __ pause();
+  %}
+  ins_pipe(pipe_slow);
+%}
+
 // ====================VECTOR INSTRUCTIONS=====================================
 
 // Load vectors (4 bytes long)
--- a/hotspot/src/share/vm/c1/c1_Compiler.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/c1/c1_Compiler.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -131,6 +131,9 @@
     if (!VM_Version::supports_atomic_getset4()) return false;
 #endif
     break;
+  case vmIntrinsics::_onSpinWait:
+    if (!VM_Version::supports_on_spin_wait()) return false;
+    break;
   case vmIntrinsics::_arraycopy:
   case vmIntrinsics::_currentTimeMillis:
   case vmIntrinsics::_nanoTime:
--- a/hotspot/src/share/vm/c1/c1_LIR.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/c1/c1_LIR.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -483,6 +483,7 @@
     case lir_membar_storestore:        // result and info always invalid
     case lir_membar_loadstore:         // result and info always invalid
     case lir_membar_storeload:         // result and info always invalid
+    case lir_on_spin_wait:
     {
       assert(op->as_Op0() != NULL, "must be");
       assert(op->_info == NULL, "info not used by this instruction");
@@ -1691,6 +1692,7 @@
      case lir_word_align:            s = "word_align";    break;
      case lir_label:                 s = "label";         break;
      case lir_nop:                   s = "nop";           break;
+     case lir_on_spin_wait:          s = "on_spin_wait";  break;
      case lir_backwardbranch_target: s = "backbranch";    break;
      case lir_std_entry:             s = "std_entry";     break;
      case lir_osr_entry:             s = "osr_entry";     break;
--- a/hotspot/src/share/vm/c1/c1_LIR.hpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/c1/c1_LIR.hpp	Wed Mar 30 17:04:14 2016 +0200
@@ -920,6 +920,7 @@
       , lir_membar_loadstore
       , lir_membar_storeload
       , lir_get_thread
+      , lir_on_spin_wait
   , end_op0
   , begin_op1
       , lir_fxch
@@ -2101,6 +2102,8 @@
   void std_entry(LIR_Opr receiver)               { append(new LIR_Op0(lir_std_entry, receiver)); }
   void osr_entry(LIR_Opr osrPointer)             { append(new LIR_Op0(lir_osr_entry, osrPointer)); }
 
+  void on_spin_wait()                            { append(new LIR_Op0(lir_on_spin_wait)); }
+
   void branch_destination(Label* lbl)            { append(new LIR_OpLabel(lbl)); }
 
   void negate(LIR_Opr from, LIR_Opr to)          { append(new LIR_Op1(lir_neg, from, to)); }
--- a/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -678,6 +678,10 @@
       get_thread(op->result_opr());
       break;
 
+    case lir_on_spin_wait:
+      on_spin_wait();
+      break;
+
     default:
       ShouldNotReachHere();
       break;
--- a/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/c1/c1_LIRAssembler.hpp	Wed Mar 30 17:04:14 2016 +0200
@@ -251,6 +251,7 @@
   void membar_storestore();
   void membar_loadstore();
   void membar_storeload();
+  void on_spin_wait();
   void get_thread(LIR_Opr result);
 
   void verify_oop_map(CodeEmitInfo* info);
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -3161,7 +3161,9 @@
   case vmIntrinsics::_fullFence :
     if (os::is_MP()) __ membar();
     break;
-
+  case vmIntrinsics::_onSpinWait:
+    __ on_spin_wait();
+    break;
   case vmIntrinsics::_Reference_get:
     do_Reference_get(x);
     break;
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed Mar 30 17:04:14 2016 +0200
@@ -889,6 +889,10 @@
    do_name(     newArray_name,                                    "newArray")                                           \
    do_signature(newArray_signature,                               "(Ljava/lang/Class;I)Ljava/lang/Object;")             \
                                                                                                                         \
+  do_intrinsic(_onSpinWait,               java_lang_Thread,       onSpinWait_name, onSpinWait_signature,         F_S)   \
+   do_name(     onSpinWait_name,                                  "onSpinWait")                                         \
+   do_alias(    onSpinWait_signature,                             void_method_signature)                                \
+                                                                                                                        \
   do_intrinsic(_copyOf,                   java_util_Arrays,       copyOf_name, copyOf_signature,                 F_S)   \
    do_name(     copyOf_name,                                     "copyOf")                                              \
    do_signature(copyOf_signature,             "([Ljava/lang/Object;ILjava/lang/Class;)[Ljava/lang/Object;")             \
--- a/hotspot/src/share/vm/opto/c2compiler.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/opto/c2compiler.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -361,6 +361,9 @@
   case vmIntrinsics::_getCallerClass:
     if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return false;
     break;
+  case vmIntrinsics::_onSpinWait:
+    if (!Matcher::match_rule_supported(Op_OnSpinWait)) return false;
+    break;
   case vmIntrinsics::_hashCode:
   case vmIntrinsics::_identityHashCode:
   case vmIntrinsics::_getClass:
--- a/hotspot/src/share/vm/opto/classes.hpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/opto/classes.hpp	Wed Mar 30 17:04:14 2016 +0200
@@ -205,6 +205,7 @@
 macro(NegD)
 macro(NegF)
 macro(NeverBranch)
+macro(OnSpinWait)
 macro(Opaque1)
 macro(Opaque2)
 macro(Opaque3)
--- a/hotspot/src/share/vm/opto/library_call.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/opto/library_call.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -280,6 +280,7 @@
   MemNode::MemOrd access_kind_to_memord(AccessKind access_kind);
   bool inline_unsafe_load_store(BasicType type,  LoadStoreKind kind, AccessKind access_kind);
   bool inline_unsafe_fence(vmIntrinsics::ID id);
+  bool inline_onspinwait();
   bool inline_fp_conversions(vmIntrinsics::ID id);
   bool inline_number_methods(vmIntrinsics::ID id);
   bool inline_reference_get();
@@ -695,6 +696,8 @@
   case vmIntrinsics::_storeFence:
   case vmIntrinsics::_fullFence:                return inline_unsafe_fence(intrinsic_id());
 
+  case vmIntrinsics::_onSpinWait:               return inline_onspinwait();
+
   case vmIntrinsics::_currentThread:            return inline_native_currentThread();
   case vmIntrinsics::_isInterrupted:            return inline_native_isInterrupted();
 
@@ -3126,6 +3129,11 @@
   }
 }
 
+bool LibraryCallKit::inline_onspinwait() {
+  insert_mem_bar(Op_OnSpinWait);
+  return true;
+}
+
 bool LibraryCallKit::klass_needs_init_guard(Node* kls) {
   if (!kls->is_Con()) {
     return true;
--- a/hotspot/src/share/vm/opto/matcher.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/opto/matcher.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -943,6 +943,7 @@
     case Op_MemBarCPUOrder: // %%% these ideals should have narrower adr_type?
     case Op_StrInflatedCopy:
     case Op_StrCompressedCopy:
+    case Op_OnSpinWait:
     case Op_EncodeISOArray:
       nidx = Compile::AliasIdxTop;
       nat = NULL;
--- a/hotspot/src/share/vm/opto/memnode.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -2978,6 +2978,7 @@
   case Op_MemBarReleaseLock: return new MemBarReleaseLockNode(C, atp, pn);
   case Op_MemBarVolatile:    return new MemBarVolatileNode(C, atp, pn);
   case Op_MemBarCPUOrder:    return new MemBarCPUOrderNode(C, atp, pn);
+  case Op_OnSpinWait:        return new OnSpinWaitNode(C, atp, pn);
   case Op_Initialize:        return new InitializeNode(C, atp, pn);
   case Op_MemBarStoreStore:  return new MemBarStoreStoreNode(C, atp, pn);
   default: ShouldNotReachHere(); return NULL;
--- a/hotspot/src/share/vm/opto/memnode.hpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/opto/memnode.hpp	Wed Mar 30 17:04:14 2016 +0200
@@ -1186,6 +1186,13 @@
   virtual uint ideal_reg() const { return 0; } // not matched in the AD file
 };
 
+class OnSpinWaitNode: public MemBarNode {
+public:
+  OnSpinWaitNode(Compile* C, int alias_idx, Node* precedent)
+    : MemBarNode(C, alias_idx, precedent) {}
+  virtual int Opcode() const;
+};
+
 // Isolation of object setup after an AllocateNode and before next safepoint.
 // (See comment in memnode.cpp near InitializeNode::InitializeNode for semantics.)
 class InitializeNode: public MemBarNode {
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Wed Mar 30 17:04:14 2016 +0200
@@ -1926,6 +1926,7 @@
   declare_c2_type(StoreFenceNode, MemBarNode)                             \
   declare_c2_type(MemBarVolatileNode, MemBarNode)                         \
   declare_c2_type(MemBarCPUOrderNode, MemBarNode)                         \
+  declare_c2_type(OnSpinWaitNode, MemBarNode)                             \
   declare_c2_type(InitializeNode, MemBarNode)                             \
   declare_c2_type(ThreadLocalNode, Node)                                  \
   declare_c2_type(Opaque1Node, Node)                                      \
--- a/hotspot/src/share/vm/runtime/vm_version.hpp	Tue Apr 05 20:32:54 2016 +0000
+++ b/hotspot/src/share/vm/runtime/vm_version.hpp	Wed Mar 30 17:04:14 2016 +0200
@@ -162,6 +162,9 @@
   // Calculates and returns the number of parallel threads.  May
   // be VM version specific.
   static unsigned int calc_parallel_worker_threads();
+
+  // Does this CPU support spin wait instruction?
+  static bool supports_on_spin_wait() { return false; }
 };
 
 #ifdef TARGET_ARCH_x86
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/onSpinWait/TestOnSpinWait.java	Wed Mar 30 17:04:14 2016 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2016 Azul Systems, Inc.  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.
+ */
+
+/**
+ * @test TestOnSpinWait
+ * @summary (x86 only) checks that java.lang.Thread.onSpinWait is intrinsified
+ * @bug 8147844
+ * @library /testlibrary
+ * @requires os.arch=="x86" | os.arch=="amd64" | os.arch=="x86_64"
+ * @run main TestOnSpinWait
+ */
+
+import java.lang.invoke.*;
+import jdk.test.lib.*;
+import static jdk.test.lib.Asserts.*;
+
+public class TestOnSpinWait {
+
+    public static void main(String[] args) throws Exception {
+
+        // Test C1 compiler
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+          "-XX:+IgnoreUnrecognizedVMOptions", "-showversion",
+          "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1", "-Xbatch",
+          "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions",
+          "-XX:+PrintInlining", "TestOnSpinWait$Launcher");
+
+        OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
+
+        analyzer.shouldHaveExitValue(0);
+
+        // The test is applicable only to C1 (present in Server VM).
+        analyzer.shouldContain("java.lang.Thread::onSpinWait (1 bytes)   intrinsic");
+
+        // Test C2 compiler
+        pb = ProcessTools.createJavaProcessBuilder(
+          "-XX:+IgnoreUnrecognizedVMOptions", "-showversion",
+          "-XX:-TieredCompilation", "-Xbatch",
+          "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions",
+          "-XX:+PrintInlining", "TestOnSpinWait$Launcher");
+
+        analyzer = new OutputAnalyzer(pb.start());
+
+        analyzer.shouldHaveExitValue(0);
+
+        // The test is applicable only to C2 (present in Server VM).
+        if (analyzer.getStderr().contains("Server VM")) {
+            analyzer.shouldContain("java.lang.Thread::onSpinWait (1 bytes)   (intrinsic)");
+        }
+    }
+
+    static class Launcher {
+
+        public static void main(final String[] args) throws Exception {
+            int end = 20_000;
+
+            for (int i=0; i < end; i++) {
+                test();
+            }
+        }
+        static void test() {
+            java.lang.Thread.onSpinWait();
+        }
+    }
+}