changeset 54492:a1bdb6bccfdd lworld

8218615: [lworld] C1 intrinsic support for System.arraycopy Reviewed-by: fparain
author iklam
date Sun, 03 Mar 2019 22:09:42 -0800
parents 370f6cd66272
children cf9a8e7a0094
files src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp src/hotspot/share/c1/c1_Compiler.cpp src/hotspot/share/c1/c1_Instruction.cpp src/hotspot/share/c1/c1_LIR.hpp src/hotspot/share/c1/c1_LIRGenerator.cpp test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrays.java
diffstat 7 files changed, 77 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Thu Feb 28 10:55:30 2019 +0100
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Sun Mar 03 22:09:42 2019 -0800
@@ -3045,6 +3045,21 @@
 }
 
 
+void LIR_Assembler::arraycopy_flat_check(Register obj, Register tmp, CodeStub* slow_path) {
+  Address klass_addr = Address(obj, oopDesc::klass_offset_in_bytes());
+  if (UseCompressedClassPointers) {
+    __ movl(tmp, klass_addr);
+    LP64_ONLY(__ decode_klass_not_null(tmp));
+  } else {
+    __ movptr(tmp, klass_addr);
+  }
+  __ movl(tmp, Address(tmp, Klass::layout_helper_offset()));
+  __ sarl(tmp, Klass::_lh_array_tag_shift);
+  __ cmpl(tmp, Klass::_lh_array_tag_vt_value);
+  __ jcc(Assembler::equal, *slow_path->entry());
+}
+
+
 // This code replaces a call to arraycopy; no exception may
 // be thrown in this code, they must be thrown in the System.arraycopy
 // activation frame; we could save some checks if this would not be the case
@@ -3065,6 +3080,30 @@
   BasicType basic_type = default_type != NULL ? default_type->element_type()->basic_type() : T_ILLEGAL;
   if (basic_type == T_ARRAY) basic_type = T_OBJECT;
 
+  if (flags & LIR_OpArrayCopy::always_slow_path) {
+    __ jmp(*stub->entry());
+    __ bind(*stub->continuation());
+    return;
+  }
+
+  if (flags & LIR_OpArrayCopy::src_flat_check) {
+    arraycopy_flat_check(src, tmp, stub);
+  }
+
+  if (flags & LIR_OpArrayCopy::dst_flat_check) {
+    arraycopy_flat_check(dst, tmp, stub);
+  }
+
+  if (basic_type == T_VALUETYPE) {
+    assert(flags & (LIR_OpArrayCopy::always_slow_path |
+                    LIR_OpArrayCopy::src_flat_check |
+                    LIR_OpArrayCopy::dst_flat_check), "must have checked");
+    // If either src or dst is (or maybe) a flattened array, one of the 3 checks
+    // above would have caught it, and taken the slow path. So when we come here,
+    // the array must be a (non-flat) object array.
+    basic_type = T_OBJECT;
+  }
+
   // if we don't know anything, just go through the generic arraycopy
   if (default_type == NULL) {
     // save outgoing arguments on stack in case call to System.arraycopy is needed
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp	Thu Feb 28 10:55:30 2019 +0100
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.hpp	Sun Mar 03 22:09:42 2019 -0800
@@ -55,6 +55,8 @@
     _deopt_handler_size = NOT_LP64(10) LP64_ONLY(17)
   };
 
+  void arraycopy_flat_check(Register obj, Register tmp, CodeStub* slow_path);
+
 public:
 
   void store_parameter(Register r,  int offset_from_esp_in_words);
--- a/src/hotspot/share/c1/c1_Compiler.cpp	Thu Feb 28 10:55:30 2019 +0100
+++ b/src/hotspot/share/c1/c1_Compiler.cpp	Sun Mar 03 22:09:42 2019 -0800
@@ -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
@@ -106,11 +106,6 @@
     return false;
   }
 
-  if (EnableValhalla && id == vmIntrinsics::_arraycopy) {
-    // FIXME: C1 doesn't support intrinsic copy of value arrays yet. Disable it for now.
-    return false;
-  }
-
   switch (id) {
   case vmIntrinsics::_compareAndSetLong:
     if (!VM_Version::supports_cx8()) return false;
--- a/src/hotspot/share/c1/c1_Instruction.cpp	Thu Feb 28 10:55:30 2019 +0100
+++ b/src/hotspot/share/c1/c1_Instruction.cpp	Sun Mar 03 22:09:42 2019 -0800
@@ -166,6 +166,9 @@
           // We will add a runtime check for flat-ness.
           return true;
         }
+      } else if (type->is_klass() && type->as_klass()->is_java_lang_Object()) {
+        // This can happen as a parameter to System.arraycopy()
+        return true;
       }
     } else if (as_Phi() != NULL) {
       // Type info gets lost during Phi merging, but we might be storing into a
--- a/src/hotspot/share/c1/c1_LIR.hpp	Thu Feb 28 10:55:30 2019 +0100
+++ b/src/hotspot/share/c1/c1_LIR.hpp	Sun Mar 03 22:09:42 2019 -0800
@@ -1273,7 +1273,10 @@
     unaligned              = 1 << 9,
     src_objarray           = 1 << 10,
     dst_objarray           = 1 << 11,
-    all_flags              = (1 << 12) - 1
+    always_slow_path       = 1 << 12,
+    src_flat_check         = 1 << 13,
+    dst_flat_check         = 1 << 14,
+    all_flags              = (1 << 15) - 1
   };
 
   LIR_OpArrayCopy(LIR_Opr src, LIR_Opr src_pos, LIR_Opr dst, LIR_Opr dst_pos, LIR_Opr length, LIR_Opr tmp,
--- a/src/hotspot/share/c1/c1_LIRGenerator.cpp	Thu Feb 28 10:55:30 2019 +0100
+++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp	Sun Mar 03 22:09:42 2019 -0800
@@ -792,6 +792,16 @@
   // of the required checks for a fast case can be elided.
   int flags = LIR_OpArrayCopy::all_flags;
 
+  if (!src->is_loaded_flattened_array() && !dst->is_loaded_flattened_array()) {
+    flags &= ~LIR_OpArrayCopy::always_slow_path;
+  }
+  if (!src->maybe_flattened_array()) {
+    flags &= ~LIR_OpArrayCopy::src_flat_check;
+  }
+  if (!dst->maybe_flattened_array()) {
+    flags &= ~LIR_OpArrayCopy::dst_flat_check;
+  }
+
   if (!src_objarray)
     flags &= ~LIR_OpArrayCopy::src_objarray;
   if (!dst_objarray)
--- a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrays.java	Thu Feb 28 10:55:30 2019 +0100
+++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestArrays.java	Sun Mar 03 22:09:42 2019 -0800
@@ -40,8 +40,20 @@
  *                               compiler.valhalla.valuetypes.TestArrays
  */
 public class TestArrays extends ValueTypeTest {
-    // Deopt of System.arraycopy is not implemented in C1
-    static boolean DEOPT_ARRAY_COPY = !(ValueTypeTest.TEST_C1);
+    // Unlike C2, C1 intrinsics never deoptimize System.arraycopy. Instead, we fall back to
+    // a normal method invocation when encountering flattened arrays.
+    private static void assertDeoptimizedByC2(Method m) {
+        int CompLevel_none              = 0,         // Interpreter
+            CompLevel_simple            = 1,         // C1
+            CompLevel_limited_profile   = 2,         // C1, invocation & backedge counters
+            CompLevel_full_profile      = 3,         // C1, invocation & backedge counters + mdo
+            CompLevel_full_optimization = 4;         // C2 or JVMCI
+
+        if (!XCOMP && WHITE_BOX.isMethodCompiled(m, false) &&
+            WHITE_BOX.getMethodCompilationLevel(m, false) >= CompLevel_full_optimization) {
+            throw new RuntimeException("Type check should have caused it to deoptimize");
+        }
+    }
 
     // Extra VM parameters for some test scenarios. See ValueTypeTest.getVMParameters()
     @Override
@@ -930,9 +942,7 @@
         verify(dst, src);
         if (!warmup) {
             Method m = tests.get("TestArrays::test38");
-            if (WHITE_BOX.isMethodCompiled(m, false) && !XCOMP && DEOPT_ARRAY_COPY) {
-                throw new RuntimeException("Type check should have caused it to deoptimize");
-            }
+            assertDeoptimizedByC2(m);
             WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION);
             test38(src, dst);
             verify(dst, src);
@@ -981,9 +991,7 @@
         verify(dst, src);
         if (!warmup) {
             Method m = tests.get("TestArrays::test40");
-            if (WHITE_BOX.isMethodCompiled(m, false) && !XCOMP && DEOPT_ARRAY_COPY) {
-                throw new RuntimeException("Type check should have caused it to deoptimize");
-            }
+            assertDeoptimizedByC2(m);
             WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION);
             test40(src, dst);
             verify(dst, src);
@@ -1115,9 +1123,7 @@
         verify(dst, src);
         if (!warmup) {
             Method m = tests.get("TestArrays::test46");
-            if (WHITE_BOX.isMethodCompiled(m, false) && !XCOMP && DEOPT_ARRAY_COPY) {
-                throw new RuntimeException("Type check should have caused it to deoptimize");
-            }
+            assertDeoptimizedByC2(m);
             WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION);
             test46(src, dst);
             verify(dst, src);
@@ -1164,9 +1170,7 @@
         verify(dst, src);
         if (!warmup) {
             Method m = tests.get("TestArrays::test48");
-            if (WHITE_BOX.isMethodCompiled(m, false) && !XCOMP && DEOPT_ARRAY_COPY) {
-                throw new RuntimeException("Type check should have caused it to deoptimize");
-            }
+            assertDeoptimizedByC2(m);
             WHITE_BOX.enqueueMethodForCompilation(m, COMP_LEVEL_FULL_OPTIMIZATION);
             test48(src, dst);
             verify(dst, src);