[aarch64-port-dev ] C1: Don't use high parts of registers in arraycopy

Andrew Haley aph at redhat.com
Mon Jan 27 02:49:01 PST 2014


This patch cleans up LIR_Assembler::emit_arraycopy so that it is not
affected by garbage in the high parts of 64-bit registers.

There was a comment at the start of emit_arraycopy:
"length and pos's are all sign extended at this point on 64bit"
This comment is not quite right.

Let's say a method is deoptimized at a call site.  Its outgoing
arguments are in registers, as per the Java calling convention.
Deoptimization copies these arguments to the stack, as per the
interpreter calling convention, but it destroys the upper half of all
32-bit registers.  These then get passed to a C1-compiled method,
which calls arraycopy, and boom.

Andrew.


# HG changeset patch
# User aph
# Date 1390583932 18000
#      Fri Jan 24 12:18:52 2014 -0500
# Node ID 1f2d6153f6c1d2cb2c3445808be069159984d968
# Parent  1e2c91a63fc3019b4958ae443ba66d6862e8e19f
C1: Don't use high parts of registers in arraycopy.

diff -r 1e2c91a63fc3 -r 1f2d6153f6c1 src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp
--- a/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp	Thu Jan 23 11:43:53 2014 -0500
+++ b/src/cpu/aarch64/vm/c1_LIRAssembler_aarch64.cpp	Fri Jan 24 12:18:52 2014 -0500
@@ -2267,8 +2267,6 @@
   Address src_klass_addr = Address(src, oopDesc::klass_offset_in_bytes());
   Address dst_klass_addr = Address(dst, oopDesc::klass_offset_in_bytes());

-  // length and pos's are all sign extended at this point on 64bit
-
   // test for NULL
   if (flags & LIR_OpArrayCopy::src_null_check) {
     __ cbz(src, *stub->entry());
@@ -2287,31 +2285,31 @@
     __ br(Assembler::LT, *stub->entry());
   }

+  if (flags & LIR_OpArrayCopy::length_positive_check) {
+    __ cmpw(length, 0);
+    __ br(Assembler::LT, *stub->entry());
+  }
+
   if (flags & LIR_OpArrayCopy::src_range_check) {
-    __ lea(tmp, Address(src_pos, length));
+    __ addw(tmp, src_pos, length);
     __ ldrw(rscratch1, src_length_addr);
     __ cmpw(tmp, rscratch1);
     __ br(Assembler::HI, *stub->entry());
   }
   if (flags & LIR_OpArrayCopy::dst_range_check) {
-    __ lea(tmp, Address(dst_pos, length));
+    __ addw(tmp, dst_pos, length);
     __ ldrw(rscratch1, dst_length_addr);
     __ cmpw(tmp, rscratch1);
     __ br(Assembler::HI, *stub->entry());
   }

-  if (flags & LIR_OpArrayCopy::length_positive_check) {
-    __ cmpw(length, 0);
-    __ br(Assembler::LT, *stub->entry());
-  }
-
   // FIXME: The logic in LIRGenerator::arraycopy_helper clears
   // length_positive_check if the source of our length operand is an
   // arraylength.  However, that arraylength might be zero, and the
   // stub that we're about to call contains an assertion that count !=
   // 0 .  So we make this check purely in order not to trigger an
   // assertion failure.
-  __ cbz(length, *stub->continuation());
+  __ cbzw(length, *stub->continuation());

   if (flags & LIR_OpArrayCopy::type_check) {
     // We don't know the array types are compatible
@@ -2384,15 +2382,13 @@
 	__ stp(length,  src_pos, Address(sp, 2*BytesPerWord));
 	__ str(src,              Address(sp, 4*BytesPerWord));

-        __ uxtw(length, length); // FIXME ??  higher 32bits must be null
-
         __ lea(c_rarg0, Address(src, src_pos, Address::uxtw(scale)));
 	__ add(c_rarg0, c_rarg0, arrayOopDesc::base_offset_in_bytes(basic_type));
         assert_different_registers(c_rarg0, dst, dst_pos, length);
         __ lea(c_rarg1, Address(dst, dst_pos, Address::uxtw(scale)));
 	__ add(c_rarg1, c_rarg1, arrayOopDesc::base_offset_in_bytes(basic_type));
         assert_different_registers(c_rarg1, dst, length);
-        __ mov(c_rarg2, length);
+        __ uxtw(c_rarg2, length);
         assert_different_registers(c_rarg2, dst);

         __ load_klass(c_rarg4, dst);
@@ -2503,7 +2499,7 @@
   __ lea(c_rarg1, Address(dst, dst_pos, Address::uxtw(scale)));
   __ add(c_rarg1, c_rarg1, arrayOopDesc::base_offset_in_bytes(basic_type));
   assert_different_registers(c_rarg1, dst, length);
-  __ mov(c_rarg2, length);
+  __ uxtw(c_rarg2, length);
   assert_different_registers(c_rarg2, dst);

   bool disjoint = (flags & LIR_OpArrayCopy::overlapping) == 0;


More information about the aarch64-port-dev mailing list