diff -r 8acd232fb52a src/cpu/aarch64/vm/macroAssembler_aarch64.cpp
--- a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Thu Aug 31 08:18:47 2017 +0200
+++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp	Tue Sep 12 15:28:42 2017 +0300
@@ -4975,6 +4975,17 @@
   // Check for short strings, i.e. smaller than wordSize.
   subs(cnt1, cnt1, elem_per_word);
   br(Assembler::LT, SHORT);
+  int prefetchThreshold = (SoftwarePrefetchHintDistance
+    + VM_Version::dcache_line_size()/2)/elem_size - elem_per_word;
+  cmp(cnt1, prefetchThreshold);
+  br(Assembler::LT, NEXT_WORD);
+  RuntimeAddress stub = elem_size == 1
+          ? RuntimeAddress(StubRoutines::aarch64::large_array_equals_byte())
+          : RuntimeAddress(StubRoutines::aarch64::large_array_equals_char());
+  assert(stub.target() != NULL, "array_equals_long_* stub has not been generated");
+  trampoline_call(stub);
+  cbz(result, DONE);
+  mov(result, false); // reset result
   // Main 8 byte comparison loop.
   bind(NEXT_WORD); {
     ldr(tmp1, Address(post(a1, wordSize)));
diff -r 8acd232fb52a src/cpu/aarch64/vm/stubGenerator_aarch64.cpp
--- a/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp	Thu Aug 31 08:18:47 2017 +0200
+++ b/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp	Tue Sep 12 15:28:42 2017 +0300
@@ -3831,6 +3831,95 @@
     __ ret(lr);
     return entry;
   }
+
+  address generate_large_array_equals_byte() {
+    return generate_large_array_equals(1);
+  }
+
+  address generate_large_array_equals_char() {
+    return generate_large_array_equals(2);
+  }
+
+  // a1 = r1 - array1 address
+  // a2 = r2 - array2 address
+  // result = r0 - return value. already contain "false" value.
+  //   return 1 if checked array parts are equal
+  // cnt1 = r10 - amount of elements left to check, reduced by elem_per_word
+  address generate_large_array_equals(int elem_size) {
+    StubCodeMark mark(this, "StubRoutines", "array_equals_long");
+    Register a1 = r1, a2 = r2, result = r0, cnt1 = r10, tmp1 = rscratch1,
+        tmp2 = rscratch2, tmp3 = r6, tmp4 = r7, tmp5 = r11, tmp6 = r12,
+        tmp7 = r13, tmp8 = r14;
+    Label LARGE_LOOP, NOT_EQUAL;
+    int elem_per_word = wordSize/elem_size;
+    int prefetchThreshold = (SoftwarePrefetchHintDistance
+        + VM_Version::dcache_line_size()/2)/elem_size - elem_per_word;
+ 
+    assert_different_registers(a1, a2, result, cnt1, tmp1, tmp2, tmp3, tmp4,
+        tmp5, tmp6, tmp7, tmp8);
+
+    __ align(CodeEntryAlignment);
+    address entry = __ pc();
+    __ enter();
+
+    // pre-loop
+    RegSet spilled_regs = RegSet::of(tmp3, tmp4) + RegSet::range(tmp5, tmp8);
+    __ push(spilled_regs, sp);
+    __ ldp(tmp1, tmp3, Address(__ post(a1, 2 * wordSize)));
+    __ ldp(tmp2, tmp4, Address(__ post(a2, 2 * wordSize)));
+    // unrolled to 64 bytes loop with prefetching
+    __ bind(LARGE_LOOP);
+      __ prfm(Address(a1, SoftwarePrefetchHintDistance));
+      __ prfm(Address(a2, SoftwarePrefetchHintDistance));
+
+      __ eor(tmp1, tmp1, tmp2);
+      __ cbnz(tmp1, NOT_EQUAL);
+      __ ldp(tmp5, tmp7, Address(__ post(a1, 2 * wordSize)));
+      __ eor(tmp3, tmp3, tmp4);
+      __ cbnz(tmp3, NOT_EQUAL);
+      __ ldp(tmp6, tmp8, Address(__ post(a2, 2 * wordSize)));
+
+      __ eor(tmp5, tmp5, tmp6);
+      __ cbnz(tmp5, NOT_EQUAL);
+      __ ldp(tmp2, tmp4, Address(__ post(a2, 2 * wordSize)));
+      __ eor(tmp7, tmp7, tmp8);
+      __ cbnz(tmp7, NOT_EQUAL);
+      __ ldp(tmp1, tmp3, Address(__ post(a1, 2 * wordSize)));
+
+      __ eor(tmp1, tmp1, tmp2);
+      __ cbnz(tmp1, NOT_EQUAL);
+      __ ldp(tmp6, tmp8, Address(__ post(a2, 2 * wordSize)));
+      __ eor(tmp3, tmp3, tmp4);
+      __ cbnz(tmp3, NOT_EQUAL);
+      __ ldp(tmp5, tmp7, Address(__ post(a1, 2 * wordSize)));
+
+      // loads below are for next loop iteration
+      __ eor(tmp5, tmp5, tmp6);
+      __ cbnz(tmp5, NOT_EQUAL);
+      __ ldp(tmp1, tmp3, Address(__ post(a1, 2 * wordSize)));
+      __ eor(tmp7, tmp7, tmp8);
+      __ cbnz(tmp7, NOT_EQUAL);
+      __ ldp(tmp2, tmp4, Address(__ post(a2, 2 * wordSize)));
+
+      __ sub(cnt1, cnt1, 8 * elem_per_word);
+      __ cmp(cnt1, prefetchThreshold);
+      __ br(Assembler::GT, LARGE_LOOP);
+      // both a1 and a2 are shifted more than needed by wordSize and tmp1-tmp4
+      // contains still-not-checked value. Check it in this post-loop, also update
+      // cnt1 accordingly
+      __ eor(tmp1, tmp1, tmp2);
+      __ cbnz(tmp1, NOT_EQUAL);
+      __ eor(tmp3, tmp3, tmp4);
+      __ cbnz(tmp3, NOT_EQUAL);
+      __ sub(cnt1, cnt1, 2 * elem_per_word);
+      __ mov(result, true);
+    __ bind(NOT_EQUAL);
+      __ pop(spilled_regs, sp);
+      __ leave();
+      __ ret(lr);
+    return entry;
+  }
+
   /**
    *  Arguments:
    *
@@ -4909,6 +4998,10 @@
     // has negatives stub for large arrays.
     StubRoutines::aarch64::_has_negatives = generate_has_negatives(StubRoutines::aarch64::_has_negatives_long);
 
+    // array equals stub for large arrays.
+    StubRoutines::aarch64::_large_array_equals_byte = generate_large_array_equals_byte();
+    StubRoutines::aarch64::_large_array_equals_char = generate_large_array_equals_char();
+
     if (UseMultiplyToLenIntrinsic) {
       StubRoutines::_multiplyToLen = generate_multiplyToLen();
     }
diff -r 8acd232fb52a src/cpu/aarch64/vm/stubRoutines_aarch64.cpp
--- a/src/cpu/aarch64/vm/stubRoutines_aarch64.cpp	Thu Aug 31 08:18:47 2017 +0200
+++ b/src/cpu/aarch64/vm/stubRoutines_aarch64.cpp	Tue Sep 12 15:28:42 2017 +0300
@@ -46,6 +46,8 @@
 address StubRoutines::aarch64::_zero_blocks = NULL;
 address StubRoutines::aarch64::_has_negatives = NULL;
 address StubRoutines::aarch64::_has_negatives_long = NULL;
+address StubRoutines::aarch64::_large_array_equals_byte = NULL;
+address StubRoutines::aarch64::_large_array_equals_char = NULL;
 bool StubRoutines::aarch64::_completed = false;
 
 /**
diff -r 8acd232fb52a src/cpu/aarch64/vm/stubRoutines_aarch64.hpp
--- a/src/cpu/aarch64/vm/stubRoutines_aarch64.hpp	Thu Aug 31 08:18:47 2017 +0200
+++ b/src/cpu/aarch64/vm/stubRoutines_aarch64.hpp	Tue Sep 12 15:28:42 2017 +0300
@@ -65,6 +65,10 @@
 
   static address _has_negatives;
   static address _has_negatives_long;
+
+  static address _large_array_equals_byte;
+  static address _large_array_equals_char;
+
   static bool _completed;
 
  public:
@@ -131,6 +135,14 @@
       return _has_negatives_long;
   }
 
+  static address large_array_equals_byte() {
+      return _large_array_equals_byte;
+  }
+
+  static address large_array_equals_char() {
+      return _large_array_equals_char;
+  }
+
   static bool complete() {
     return _completed;
   }
