diff a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
@@ -5028,12 +5028,12 @@
 // Input:
 // src - the oop we want to load the klass from.
 // dst - output narrow klass.
 void MacroAssembler::load_narrow_klass_compact(Register dst, Register src) {
   assert(UseCompactObjectHeaders, "expects UseCompactObjectHeaders");
-  ldr(dst, Address(src, oopDesc::mark_offset_in_bytes()));
-  lsr(dst, dst, markWord::klass_shift);
+  ldrw(dst, Address(src, oopDesc::mark_offset_in_bytes()));
+  lsrw(dst, dst, markWord::klass_shift);
 }
 
 void MacroAssembler::load_klass(Register dst, Register src) {
   if (UseCompactObjectHeaders) {
     load_narrow_klass_compact(dst, src);
@@ -5823,26 +5823,16 @@
                                       Register tmp4, Register tmp5, Register result,
                                       Register cnt1, int elem_size) {
   Label DONE, SAME;
   Register tmp1 = rscratch1;
   Register tmp2 = rscratch2;
+  Register cnt2 = tmp2;  // cnt2 only used in array length compare
   int elem_per_word = wordSize/elem_size;
   int log_elem_size = exact_log2(elem_size);
-  int klass_offset  = arrayOopDesc::klass_offset_in_bytes();
   int length_offset = arrayOopDesc::length_offset_in_bytes();
   int base_offset
     = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE);
-  // When the length offset is not aligned to 8 bytes,
-  // then we align it down. This is valid because the new
-  // offset will always be the klass which is the same
-  // for type arrays.
-  int start_offset = align_down(length_offset, BytesPerWord);
-  int extra_length = base_offset - start_offset;
-  assert(start_offset == length_offset || start_offset == klass_offset,
-         "start offset must be 8-byte-aligned or be the klass offset");
-  assert(base_offset != start_offset, "must include the length field");
-  extra_length = extra_length / elem_size; // We count in elements, not bytes.
   int stubBytesThreshold = 3 * 64 + (UseSIMDForArrayEquals ? 0 : 16);
 
   assert(elem_size == 1 || elem_size == 2, "must be char or byte");
   assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2);
 
@@ -5872,14 +5862,15 @@
     br(EQ, A_MIGHT_BE_NULL);
     // if (a1.length != a2.length)
     //      return false;
     bind(A_IS_NOT_NULL);
     ldrw(cnt1, Address(a1, length_offset));
-    // Increase loop counter by diff between base- and actual start-offset.
-    addw(cnt1, cnt1, extra_length);
-    lea(a1, Address(a1, start_offset));
-    lea(a2, Address(a2, start_offset));
+    ldrw(cnt2, Address(a2, length_offset));
+    eorw(tmp5, cnt1, cnt2);
+    cbnzw(tmp5, DONE);
+    lea(a1, Address(a1, base_offset));
+    lea(a2, Address(a2, base_offset));
     // Check for short strings, i.e. smaller than wordSize.
     subs(cnt1, cnt1, elem_per_word);
     br(Assembler::LT, SHORT);
     // Main 8 byte comparison loop.
     bind(NEXT_WORD); {
@@ -5938,22 +5929,22 @@
         CSET_EQ, LAST_CHECK;
     mov(result, false);
     cbz(a1, DONE);
     ldrw(cnt1, Address(a1, length_offset));
     cbz(a2, DONE);
-    // Increase loop counter by diff between base- and actual start-offset.
-    addw(cnt1, cnt1, extra_length);
-
+    ldrw(cnt2, Address(a2, length_offset));
     // on most CPUs a2 is still "locked"(surprisingly) in ldrw and it's
     // faster to perform another branch before comparing a1 and a2
     cmp(cnt1, (u1)elem_per_word);
     br(LE, SHORT); // short or same
-    ldr(tmp3, Address(pre(a1, start_offset)));
+    ldr(tmp3, Address(pre(a1, base_offset)));
     subs(zr, cnt1, stubBytesThreshold);
     br(GE, STUB);
-    ldr(tmp4, Address(pre(a2, start_offset)));
+    ldr(tmp4, Address(pre(a2, base_offset)));
     sub(tmp5, zr, cnt1, LSL, 3 + log_elem_size);
+    cmp(cnt2, cnt1);
+    br(NE, DONE);
 
     // Main 16 byte comparison loop with 2 exits
     bind(NEXT_DWORD); {
       ldr(tmp1, Address(pre(a1, wordSize)));
       ldr(tmp2, Address(pre(a2, wordSize)));
@@ -5981,11 +5972,13 @@
     eor(tmp2, tmp1, tmp2);
     cbnz(tmp2, DONE);
     b(LAST_CHECK);
 
     bind(STUB);
-    ldr(tmp4, Address(pre(a2, start_offset)));
+    ldr(tmp4, Address(pre(a2, base_offset)));
+    cmp(cnt2, cnt1);
+    br(NE, DONE);
     if (elem_size == 2) { // convert to byte counter
       lsl(cnt1, cnt1, 1);
     }
     eor(tmp5, tmp3, tmp4);
     cbnz(tmp5, DONE);
@@ -6002,13 +5995,16 @@
     // (a1 != null && a2 == null) || (a1 != null && a2 != null && a1 == a2)
     // so, if a2 == null => return false(0), else return true, so we can return a2
     mov(result, a2);
     b(DONE);
     bind(SHORT);
+    cmp(cnt2, cnt1);
+    br(NE, DONE);
+    cbz(cnt1, SAME);
     sub(tmp5, zr, cnt1, LSL, 3 + log_elem_size);
-    ldr(tmp3, Address(a1, start_offset));
-    ldr(tmp4, Address(a2, start_offset));
+    ldr(tmp3, Address(a1, base_offset));
+    ldr(tmp4, Address(a2, base_offset));
     bind(LAST_CHECK);
     eor(tmp4, tmp3, tmp4);
     lslv(tmp5, tmp4, tmp5);
     cmp(tmp5, zr);
     bind(CSET_EQ);
