changeset 58244:370822016750

8238759: Clones should always keep the base pointer Reviewed-by: rkennke, thartmann
author neliasso
date Tue, 03 Mar 2020 10:29:05 +0100
parents d765d242df98
children 1bc5f223df65
files src/hotspot/share/gc/shared/c2/barrierSetC2.cpp src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp src/hotspot/share/opto/arraycopynode.cpp test/hotspot/jtreg/compiler/arguments/TestStressReflectiveCode.java
diffstat 5 files changed, 69 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp	Tue Mar 03 13:31:33 2020 +0530
+++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.cpp	Tue Mar 03 10:29:05 2020 +0100
@@ -653,7 +653,7 @@
   // Exclude the header but include array length to copy by 8 bytes words.
   // Can't use base_offset_in_bytes(bt) since basic type is unknown.
   int base_off = is_array ? arrayOopDesc::length_offset_in_bytes() :
-                 instanceOopDesc::base_offset_in_bytes();
+                            instanceOopDesc::base_offset_in_bytes();
   // base_off:
   // 8  - 32-bit VM
   // 12 - 64-bit VM, compressed klass
@@ -674,17 +674,11 @@
 
 void BarrierSetC2::clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* size, bool is_array) const {
   int base_off = arraycopy_payload_base_offset(is_array);
-  Node* payload_src = kit->basic_plus_adr(src_base,  base_off);
-  Node* payload_dst = kit->basic_plus_adr(dst_base, base_off);
-
-  // Compute the length also, if needed:
   Node* payload_size = size;
-  payload_size = kit->gvn().transform(new SubXNode(payload_size, kit->MakeConX(base_off)));
-  payload_size = kit->gvn().transform(new URShiftXNode(payload_size, kit->intcon(LogBytesPerLong) ));
-
-  const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;
-
-  ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, payload_src, NULL, payload_dst, NULL, payload_size, true, false);
+  Node* offset = kit->MakeConX(base_off);
+  payload_size = kit->gvn().transform(new SubXNode(payload_size, offset));
+  payload_size = kit->gvn().transform(new URShiftXNode(payload_size, kit->intcon(LogBytesPerLong)));
+  ArrayCopyNode* ac = ArrayCopyNode::make(kit, false, src_base, offset,  dst_base, offset, payload_size, true, false);
   if (is_array) {
     ac->set_clone_array();
   } else {
@@ -692,6 +686,7 @@
   }
   Node* n = kit->gvn().transform(ac);
   if (n == ac) {
+    const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;
     ac->_adr_type = TypeRawPtr::BOTTOM;
     kit->set_predefined_output_for_runtime_call(ac, ac->in(TypeFunc::Memory), raw_adr_type);
   } else {
@@ -837,18 +832,16 @@
   Node* dest_offset = ac->in(ArrayCopyNode::DestPos);
   Node* length = ac->in(ArrayCopyNode::Length);
 
-  assert (src_offset == NULL,  "for clone offsets should be null");
-  assert (dest_offset == NULL, "for clone offsets should be null");
+  Node* payload_src = phase->basic_plus_adr(src, src_offset);
+  Node* payload_dst = phase->basic_plus_adr(dest, dest_offset);
 
   const char* copyfunc_name = "arraycopy";
-  address     copyfunc_addr =
-          phase->basictype2arraycopy(T_LONG, NULL, NULL,
-                              true, copyfunc_name, true);
+  address     copyfunc_addr = phase->basictype2arraycopy(T_LONG, NULL, NULL, true, copyfunc_name, true);
 
   const TypePtr* raw_adr_type = TypeRawPtr::BOTTOM;
   const TypeFunc* call_type = OptoRuntime::fast_arraycopy_Type();
 
-  Node* call = phase->make_leaf_call(ctrl, mem, call_type, copyfunc_addr, copyfunc_name, raw_adr_type, src, dest, length XTOP);
+  Node* call = phase->make_leaf_call(ctrl, mem, call_type, copyfunc_addr, copyfunc_name, raw_adr_type, payload_src, payload_dst, length XTOP);
   phase->transform_later(call);
 
   phase->igvn().replace_node(ac, call);
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp	Tue Mar 03 13:31:33 2020 +0530
+++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp	Tue Mar 03 10:29:05 2020 +0100
@@ -816,14 +816,14 @@
 void ShenandoahBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const {
   Node* ctrl = ac->in(TypeFunc::Control);
   Node* mem = ac->in(TypeFunc::Memory);
-  Node* src = ac->in(ArrayCopyNode::Src);
+  Node* src_base = ac->in(ArrayCopyNode::Src);
   Node* src_offset = ac->in(ArrayCopyNode::SrcPos);
-  Node* dest = ac->in(ArrayCopyNode::Dest);
+  Node* dest_base = ac->in(ArrayCopyNode::Dest);
   Node* dest_offset = ac->in(ArrayCopyNode::DestPos);
   Node* length = ac->in(ArrayCopyNode::Length);
-  assert (src_offset == NULL && dest_offset == NULL, "for clone offsets should be null");
-  assert (src->is_AddP(), "for clone the src should be the interior ptr");
-  assert (dest->is_AddP(), "for clone the dst should be the interior ptr");
+
+  Node* src = phase->basic_plus_adr(src_base, src_offset);
+  Node* dest = phase->basic_plus_adr(dest_base, dest_offset);
 
   if (ShenandoahCloneBarrier && clone_needs_barrier(src, phase->igvn())) {
     // Check if heap is has forwarded objects. If it does, we need to call into the special
@@ -860,7 +860,7 @@
                     CAST_FROM_FN_PTR(address, ShenandoahRuntime::shenandoah_clone_barrier),
                     "shenandoah_clone",
                     TypeRawPtr::BOTTOM,
-                    src->in(AddPNode::Base));
+                    src_base);
     call = phase->transform_later(call);
 
     ctrl = phase->transform_later(new ProjNode(call, TypeFunc::Control));
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp	Tue Mar 03 13:31:33 2020 +0530
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp	Tue Mar 03 10:29:05 2020 +0100
@@ -233,22 +233,6 @@
   return TypeFunc::make(domain, range);
 }
 
-// Node n is pointing to the start of oop payload - return base pointer
-static Node* get_base_for_arracycopy_clone(PhaseMacroExpand* phase, Node* n) {
-  // This would normally be handled by optimizations, but the type system
-  // checks get confused when it thinks it already has a base pointer.
-  const int base_offset = BarrierSetC2::arraycopy_payload_base_offset(false);
-
-  if (n->is_AddP() &&
-      n->in(AddPNode::Offset)->is_Con() &&
-      n->in(AddPNode::Offset)->get_long() == base_offset) {
-    assert(n->in(AddPNode::Base) == n->in(AddPNode::Address), "Sanity check");
-    return n->in(AddPNode::Base);
-  } else {
-    return phase->basic_plus_adr(n, phase->longcon(-base_offset));
-  }
-}
-
 void ZBarrierSetC2::clone_at_expansion(PhaseMacroExpand* phase, ArrayCopyNode* ac) const {
   Node* const src = ac->in(ArrayCopyNode::Src);
   if (ac->is_clone_array()) {
@@ -258,24 +242,16 @@
   }
 
   // Clone instance
-  assert(ac->is_clone_inst(), "Sanity check");
-
   Node* const ctrl       = ac->in(TypeFunc::Control);
   Node* const mem        = ac->in(TypeFunc::Memory);
   Node* const dst        = ac->in(ArrayCopyNode::Dest);
-  Node* const src_offset = ac->in(ArrayCopyNode::SrcPos);
-  Node* const dst_offset = ac->in(ArrayCopyNode::DestPos);
   Node* const size       = ac->in(ArrayCopyNode::Length);
 
-  assert(src_offset == NULL, "Should be null");
-  assert(dst_offset == NULL, "Should be null");
+  assert(ac->is_clone_inst(), "Sanity check");
   assert(size->bottom_type()->is_long(), "Should be long");
 
-  // The src and dst point to the object payload rather than the object base
-  Node* const src_base = get_base_for_arracycopy_clone(phase, src);
-  Node* const dst_base = get_base_for_arracycopy_clone(phase, dst);
-
-  // The size must also be increased to match the instance size
+  // The native clone we are calling here expects the instance size in words
+  // Add header/offset size to payload size to get instance size.
   Node* const base_offset = phase->longcon(arraycopy_payload_base_offset(false) >> LogBytesPerLong);
   Node* const full_size = phase->transform_later(new AddLNode(size, base_offset));
 
@@ -285,8 +261,8 @@
                                            ZBarrierSetRuntime::clone_addr(),
                                            "ZBarrierSetRuntime::clone",
                                            TypeRawPtr::BOTTOM,
-                                           src_base,
-                                           dst_base,
+                                           src,
+                                           dst,
                                            full_size,
                                            phase->top());
   phase->transform_later(call);
--- a/src/hotspot/share/opto/arraycopynode.cpp	Tue Mar 03 13:31:33 2020 +0530
+++ b/src/hotspot/share/opto/arraycopynode.cpp	Tue Mar 03 10:29:05 2020 +0100
@@ -57,7 +57,7 @@
                                    Node* src_length, Node* dest_length) {
 
   ArrayCopyNode* ac = new ArrayCopyNode(kit->C, alloc_tightly_coupled, has_negative_length_guard);
-  Node* prev_mem = kit->set_predefined_input_for_runtime_call(ac);
+  kit->set_predefined_input_for_runtime_call(ac);
 
   ac->init_req(ArrayCopyNode::Src, src);
   ac->init_req(ArrayCopyNode::SrcPos, src_offset);
@@ -176,17 +176,12 @@
     return NULL;
   }
 
-  Node* src = in(ArrayCopyNode::Src);
-  Node* dest = in(ArrayCopyNode::Dest);
+  Node* base_src = in(ArrayCopyNode::Src);
+  Node* base_dest = in(ArrayCopyNode::Dest);
   Node* ctl = in(TypeFunc::Control);
   Node* in_mem = in(TypeFunc::Memory);
 
-  const Type* src_type = phase->type(src);
-
-  assert(src->is_AddP(), "should be base + off");
-  assert(dest->is_AddP(), "should be base + off");
-  Node* base_src = src->in(AddPNode::Base);
-  Node* base_dest = dest->in(AddPNode::Base);
+  const Type* src_type = phase->type(base_src);
 
   MergeMemNode* mem = MergeMemNode::make(in_mem);
 
@@ -208,7 +203,6 @@
   BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
   for (int i = 0; i < count; i++) {
     ciField* field = ik->nonstatic_field_at(i);
-    int fieldidx = phase->C->alias_type(field)->index();
     const TypePtr* adr_type = phase->C->alias_type(field)->adr_type();
     Node* off = phase->MakeConX(field->offset());
     Node* next_src = phase->transform(new AddPNode(base_src,base_src,off));
@@ -247,16 +241,17 @@
                                        BasicType& copy_type,
                                        const Type*& value_type,
                                        bool& disjoint_bases) {
-  Node* src = in(ArrayCopyNode::Src);
-  Node* dest = in(ArrayCopyNode::Dest);
-  const Type* src_type = phase->type(src);
+  base_src = in(ArrayCopyNode::Src);
+  base_dest = in(ArrayCopyNode::Dest);
+  const Type* src_type = phase->type(base_src);
   const TypeAryPtr* ary_src = src_type->isa_aryptr();
 
+  Node* src_offset = in(ArrayCopyNode::SrcPos);
+  Node* dest_offset = in(ArrayCopyNode::DestPos);
+
   if (is_arraycopy() || is_copyofrange() || is_copyof()) {
-    const Type* dest_type = phase->type(dest);
+    const Type* dest_type = phase->type(base_dest);
     const TypeAryPtr* ary_dest = dest_type->isa_aryptr();
-    Node* src_offset = in(ArrayCopyNode::SrcPos);
-    Node* dest_offset = in(ArrayCopyNode::DestPos);
 
     // newly allocated object is guaranteed to not overlap with source object
     disjoint_bases = is_alloc_tightly_coupled();
@@ -286,15 +281,9 @@
 
     value_type = ary_src->elem();
 
-    base_src = src;
-    base_dest = dest;
-
     uint shift  = exact_log2(type2aelembytes(dest_elem));
     uint header = arrayOopDesc::base_offset_in_bytes(dest_elem);
 
-    adr_src = src;
-    adr_dest = dest;
-
     src_offset = Compile::conv_I2X_index(phase, src_offset, ary_src->size());
     dest_offset = Compile::conv_I2X_index(phase, dest_offset, ary_dest->size());
     if (src_offset->is_top() || dest_offset->is_top()) {
@@ -302,17 +291,14 @@
       return false;
     }
 
-    Node* src_scale = phase->transform(new LShiftXNode(src_offset, phase->intcon(shift)));
+    Node* src_scale  = phase->transform(new LShiftXNode(src_offset, phase->intcon(shift)));
     Node* dest_scale = phase->transform(new LShiftXNode(dest_offset, phase->intcon(shift)));
 
-    adr_src = phase->transform(new AddPNode(base_src, adr_src, src_scale));
-    adr_dest = phase->transform(new AddPNode(base_dest, adr_dest, dest_scale));
+    adr_src          = phase->transform(new AddPNode(base_src, base_src, src_scale));
+    adr_dest         = phase->transform(new AddPNode(base_dest, base_dest, dest_scale));
 
-    adr_src = new AddPNode(base_src, adr_src, phase->MakeConX(header));
-    adr_dest = new AddPNode(base_dest, adr_dest, phase->MakeConX(header));
-
-    adr_src = phase->transform(adr_src);
-    adr_dest = phase->transform(adr_dest);
+    adr_src          = phase->transform(new AddPNode(base_src, adr_src, phase->MakeConX(header)));
+    adr_dest         = phase->transform(new AddPNode(base_dest, adr_dest, phase->MakeConX(header)));
 
     copy_type = dest_elem;
   } else {
@@ -320,29 +306,31 @@
     assert(is_clonebasic(), "should be");
 
     disjoint_bases = true;
-    assert(src->is_AddP(), "should be base + off");
-    assert(dest->is_AddP(), "should be base + off");
-    adr_src = src;
-    base_src = src->in(AddPNode::Base);
-    adr_dest = dest;
-    base_dest = dest->in(AddPNode::Base);
 
-    assert(phase->type(src->in(AddPNode::Offset))->is_intptr_t()->get_con() == phase->type(dest->in(AddPNode::Offset))->is_intptr_t()->get_con(), "same start offset?");
+    adr_src  = phase->transform(new AddPNode(base_src, base_src, src_offset));
+    adr_dest = phase->transform(new AddPNode(base_dest, base_dest, dest_offset));
+
     BasicType elem = ary_src->klass()->as_array_klass()->element_type()->basic_type();
-    if (is_reference_type(elem))  elem = T_OBJECT;
+    if (is_reference_type(elem)) {
+      elem = T_OBJECT;
+    }
 
     BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
     if (bs->array_copy_requires_gc_barriers(true, elem, true, BarrierSetC2::Optimization)) {
       return false;
     }
 
-    int diff = arrayOopDesc::base_offset_in_bytes(elem) - phase->type(src->in(AddPNode::Offset))->is_intptr_t()->get_con();
+    // The address is offseted to an aligned address where a raw copy would start.
+    // If the clone copy is decomposed into load-stores - the address is adjusted to
+    // point at where the array starts.
+    const Type* toff = phase->type(src_offset);
+    int offset = toff->isa_long() ? (int) toff->is_long()->get_con() : (int) toff->is_int()->get_con();
+    int diff = arrayOopDesc::base_offset_in_bytes(elem) - offset;
     assert(diff >= 0, "clone should not start after 1st array element");
     if (diff > 0) {
       adr_src = phase->transform(new AddPNode(base_src, adr_src, phase->MakeConX(diff)));
       adr_dest = phase->transform(new AddPNode(base_dest, adr_dest, phase->MakeConX(diff)));
     }
-
     copy_type = elem;
     value_type = ary_src->elem();
   }
@@ -535,8 +523,8 @@
          in(ArrayCopyNode::Src) != NULL &&
          in(ArrayCopyNode::Dest) != NULL &&
          in(ArrayCopyNode::Length) != NULL &&
-         ((in(ArrayCopyNode::SrcPos) != NULL && in(ArrayCopyNode::DestPos) != NULL) ||
-          is_clonebasic()), "broken inputs");
+         in(ArrayCopyNode::SrcPos) != NULL &&
+         in(ArrayCopyNode::DestPos) != NULL, "broken inputs");
 
   if (in(TypeFunc::Control)->is_top() ||
       in(TypeFunc::Memory)->is_top() ||
@@ -582,7 +570,6 @@
     in_mem = MergeMemNode::make(in_mem);
   }
 
-
   if (can_reshape) {
     assert(!phase->is_IterGVN()->delay_transform(), "cannot delay transforms");
     phase->is_IterGVN()->set_delay_transform(true);
--- a/test/hotspot/jtreg/compiler/arguments/TestStressReflectiveCode.java	Tue Mar 03 13:31:33 2020 +0530
+++ b/test/hotspot/jtreg/compiler/arguments/TestStressReflectiveCode.java	Tue Mar 03 10:29:05 2020 +0100
@@ -35,8 +35,25 @@
 
     public static void main(String[] args) {
         VALUES.clone();
+        VALUES2.clone();
     }
 
-    private static final int[] VALUES = new int[]{3, 4, 5};
+    public static class Payload implements Cloneable {
+        int i1;
+        int i2;
+        int i3;
+        int i4;
+
+        public Object clone() {
+          try {
+            return super.clone();
+          } catch (CloneNotSupportedException e) {
+          }
+          return null;
+        }
+    }
+
+    private static final int[]   VALUES = new int[]{3, 4, 5};
+    private static final Payload VALUES2 = new Payload();
 }