changeset 54664:5979964785ae lworld

8215560: [lworld] Investigate if method handle calls can be further optimized Reviewed-by: thartmann
author roland
date Fri, 22 Feb 2019 17:15:23 +0100
parents d066f85c2401
children 034ed135254d
files src/hotspot/share/opto/castnode.cpp src/hotspot/share/opto/compile.cpp src/hotspot/share/opto/valuetypenode.cpp src/hotspot/share/opto/valuetypenode.hpp test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java
diffstat 5 files changed, 61 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/opto/castnode.cpp	Thu Mar 14 10:40:00 2019 +0100
+++ b/src/hotspot/share/opto/castnode.cpp	Fri Feb 22 17:15:23 2019 +0100
@@ -286,6 +286,9 @@
 //------------------------------Identity---------------------------------------
 // If input is already higher or equal to cast type, then this is an identity.
 Node* CheckCastPPNode::Identity(PhaseGVN* phase) {
+  if (in(1)->is_ValueTypeBase() && _type->isa_oopptr() && phase->type(in(1))->value_klass()->is_subtype_of(_type->is_oopptr()->klass())) {
+    return in(1);
+  }
   Node* dom = dominating_cast(phase, phase);
   if (dom != NULL) {
     return dom;
--- a/src/hotspot/share/opto/compile.cpp	Thu Mar 14 10:40:00 2019 +0100
+++ b/src/hotspot/share/opto/compile.cpp	Fri Feb 22 17:15:23 2019 +0100
@@ -2070,6 +2070,32 @@
   }
 }
 
+// Does the return value keep otherwise useless value type allocations
+// alive?
+static bool return_val_keeps_allocations_alive(Node* ret_val) {
+  ResourceMark rm;
+  Unique_Node_List wq;
+  wq.push(ret_val);
+  bool some_allocations = false;
+  for (uint i = 0; i < wq.size(); i++) {
+    Node* n = wq.at(i);
+    assert(!n->is_ValueTypeBase(), "chain of value type nodes");
+    if (n->outcnt() > 1) {
+      // Some other use for the allocation
+      return false;
+    } else if (n->is_Phi()) {
+      for (uint j = 1; j < n->req(); j++) {
+        wq.push(n->in(j));
+      }
+    } else if (n->is_CheckCastPP() &&
+               n->in(1)->is_Proj() &&
+               n->in(1)->in(0)->is_Allocate()) {
+      some_allocations = true;
+    }
+  }
+  return some_allocations;
+}
+
 void Compile::process_value_types(PhaseIterGVN &igvn) {
   // Make value types scalar in safepoints
   while (_value_type_nodes->size() != 0) {
@@ -2077,13 +2103,30 @@
     vt->make_scalar_in_safepoints(&igvn);
     if (vt->is_ValueTypePtr()) {
       igvn.replace_node(vt, vt->get_oop());
-    } else {
-      if (vt->outcnt() == 0) {
-        igvn.remove_dead_node(vt);
+    } else if (vt->outcnt() == 0) {
+      igvn.remove_dead_node(vt);
+    }
+  }
+  _value_type_nodes = NULL;
+  if (tf()->returns_value_type_as_fields()) {
+    Node* ret = NULL;
+    for (uint i = 1; i < root()->req(); i++){
+      Node* in = root()->in(i);
+      if (in->Opcode() == Op_Return) {
+        assert(ret == NULL, "only one return");
+        ret = in;
       }
     }
-  }
-  _value_type_nodes = NULL;
+    if (ret != NULL) {
+      Node* ret_val = ret->in(TypeFunc::Parms);
+      if (igvn.type(ret_val)->isa_oopptr() &&
+          return_val_keeps_allocations_alive(ret_val)) {
+        igvn.replace_input_of(ret, TypeFunc::Parms, ValueTypeNode::tagged_klass(igvn.type(ret_val)->value_klass(), igvn));
+        assert(ret_val->outcnt() == 0, "should be dead now");
+        igvn.remove_dead_node(ret_val);
+      }
+    }
+  }
   igvn.optimize();
 }
 
--- a/src/hotspot/share/opto/valuetypenode.cpp	Thu Mar 14 10:40:00 2019 +0100
+++ b/src/hotspot/share/opto/valuetypenode.cpp	Fri Feb 22 17:15:23 2019 +0100
@@ -662,8 +662,7 @@
   return vt;
 }
 
-Node* ValueTypeNode::tagged_klass(PhaseGVN& gvn) {
-  ciValueKlass* vk = value_klass();
+Node* ValueTypeNode::tagged_klass(ciValueKlass* vk, PhaseGVN& gvn) {
   const TypeKlassPtr* tk = TypeKlassPtr::make(vk);
   intptr_t bits = tk->get_con();
   set_nth_bit(bits, 0);
--- a/src/hotspot/share/opto/valuetypenode.hpp	Thu Mar 14 10:40:00 2019 +0100
+++ b/src/hotspot/share/opto/valuetypenode.hpp	Fri Feb 22 17:15:23 2019 +0100
@@ -134,7 +134,10 @@
   // Allocate all non-flattened value type fields
   Node* allocate_fields(GraphKit* kit);
 
-  Node* tagged_klass(PhaseGVN& gvn);
+  Node* tagged_klass(PhaseGVN& gvn) {
+    return tagged_klass(value_klass(), gvn);
+  }
+  static Node* tagged_klass(ciValueKlass* vk, PhaseGVN& gvn);
   // Pass value type as fields at a call or return
   void pass_fields(GraphKit* kit, Node* n, ExtendedSignature& sig, uint& base_input, int base_offset = 0);
   // Initialize the value type fields with the inputs or outputs of a MultiNode
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java	Thu Mar 14 10:40:00 2019 +0100
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestMethodHandles.java	Fri Feb 22 17:15:23 2019 +0100
@@ -37,7 +37,6 @@
  * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  *                               -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla
- *                               -DVerifyIR=false
  *                               compiler.valhalla.valuetypes.ValueTypeTest
  *                               compiler.valhalla.valuetypes.TestMethodHandles
  */
@@ -150,7 +149,7 @@
     static final MethodHandle test1_mh;
 
     @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + CALL)
-    @Test(valid = ValueTypeReturnedAsFieldsOff, match = { ALLOC, STORE }, matchCount = { 1, 12 })
+    @Test(valid = ValueTypeReturnedAsFieldsOff, match = { ALLOC, STORE }, matchCount = { 1, 14 })
     public MyValue3 test1() throws Throwable {
         return (MyValue3)test1_mh.invokeExact(this);
     }
@@ -311,8 +310,7 @@
     static final MethodHandle test7_mh;
     static MethodHandle test7_mh1;
 
-    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS)
-    @Test(valid = ValueTypeReturnedAsFieldsOff)
+    @Test
     public long test7() throws Throwable {
         return ((MyValue2)test7_mh.invokeExact(test7_mh1)).hash();
     }
@@ -345,8 +343,7 @@
     static final MethodHandle test8_mh;
     static MethodHandle test8_mh2;
 
-    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS)
-    @Test(valid = ValueTypeReturnedAsFieldsOff)
+    @Test
     public long test8() throws Throwable {
         return ((MyValue2)test8_mh.invokeExact(test8_mh2)).hash();
     }
@@ -440,8 +437,7 @@
     static MethodHandle test10_mh2;
     static MethodHandle test10_mh3;
 
-    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS)
-    @Test(valid = ValueTypeReturnedAsFieldsOff)
+    @Test
     public long test10() throws Throwable {
         return ((MyValue2)test10_mh.invokeExact(test10_mh2, test10_mh3)).hash();
     }
@@ -481,8 +477,7 @@
 
     // Check that a buffered value returned by a compiled lambda form
     // is properly handled by the caller.
-    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + ALLOCA + STORE + STOREVALUETYPEFIELDS)
-    @Test(valid = ValueTypeReturnedAsFieldsOff)
+    @Test
     @Warmup(11000)
     public long test11() throws Throwable {
         return ((MyValue2)test11_mh.invokeExact(test11_mh2)).hash();