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	Mon Sep 11 13:29:24 2017 +0300
@@ -4926,7 +4926,8 @@
                                    Register result, Register cnt1,
                                    int elem_size, bool is_string)
 {
-  Label SAME, DONE, SHORT, NEXT_WORD, ONE;
+  Label SAME, DONE, SHORT, NEXT_WORD, ONE, LARGE_LOOP, LARGE_PRELOOP, LOOP_EXIT,
+    LARGE_LOOP2, LARGE_PRELOOP2;
   Register tmp1 = rscratch1;
   Register tmp2 = rscratch2;
   Register cnt2 = tmp2;  // cnt2 only used in array length compare
@@ -4937,7 +4938,7 @@
     = arrayOopDesc::base_offset_in_bytes(elem_size == 2 ? T_CHAR : T_BYTE);
 
   assert(elem_size == 1 || elem_size == 2, "must be char or byte");
-  assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2);
+  assert_different_registers(a1, a2, result, cnt1, rscratch1, rscratch2, r6, r7, r11);
 
 #ifndef PRODUCT
   {
@@ -4975,6 +4976,106 @@
   // Check for short strings, i.e. smaller than wordSize.
   subs(cnt1, cnt1, elem_per_word);
   br(Assembler::LT, SHORT);
+  // calculate minimal size(prefetch threshold) to enable prefetch logic(so,
+  // at least half of prefetched cache line after SoftwarePrefetchHintDistance
+  // is used. Take substracted elem_per_word into consideration too.
+  int prefetchThreshold = (SoftwarePrefetchHintDistance
+    + VM_Version::dcache_line_size()/2)/elem_size - elem_per_word;
+  cmp(cnt1, prefetchThreshold);
+  br(Assembler::LT, NEXT_WORD);
+  // unrolled to 64 bytes loop with prefetching
+  // first, check if we're using 16-byte aligned access, since arrays are
+  // allocated at 8-bytes alignment, but a number of armv8 cpus have penalty
+  // when crossing 16-byte boundary for load/store. So, we'll align loads for
+  // at least a1 array
+  tbz(a1, 3, LARGE_PRELOOP);
+  ldr(tmp1, Address(post(a1, wordSize)));
+  ldr(tmp2, Address(post(a2, wordSize)));
+  eor(tmp1, tmp1, tmp2);
+  cbnz(tmp1, DONE);
+  sub(cnt1, cnt1, elem_per_word);
+  bind(LARGE_PRELOOP);
+    Register tmp3 = r6;
+    Register tmp4 = r7;
+    Register tmp5 = r11;
+    // TODO: tmp5 should be saved in (PRE/POST)LOOP2 only
+    RegSet spilled_regs = RegSet::of(tmp3, tmp4, tmp5);
+    push(spilled_regs, sp);
+    // now, a2 can be 16 or 8 byte aligned. Handle it differently.
+    tbz(a2, 3, LARGE_PRELOOP2);
+  bind(LARGE_LOOP);
+    prfm(Address(a1, SoftwarePrefetchHintDistance));
+    prfm(Address(a2, SoftwarePrefetchHintDistance));
+    ld1(v0, v1, v2, v3, T2D, Address(post(a1, 8 * wordSize)));
+    ld1(v4, v5, v6, v7, T2D, Address(post(a2, 8 * wordSize)));
+    eor(v0, T2D, v0, v4);
+    eor(v1, T2D, v1, v5);
+    eor(v2, T2D, v2, v6);
+    eor(v3, T2D, v3, v7);
+    orr(v0, T2D, v0, v1);
+    orr(v1, T2D, v2, v3);
+    orr(v0, T2D, v1, v0);
+    umov(tmp1, v0, D, 0);
+    cbnz(tmp1, LOOP_EXIT);
+    umov(tmp2, v0, D, 1);
+    cbnz(tmp2, LOOP_EXIT);
+  
+    sub(cnt1, cnt1, 64/elem_size);
+    cmp(cnt1, prefetchThreshold);
+    br(Assembler::GT, LARGE_LOOP);
+    pop(spilled_regs, sp);
+    b(NEXT_WORD);
+  bind(LARGE_PRELOOP2);
+    ldr(tmp5, Address(post(a2, wordSize))); // now a2 will be 16-byte aligned
+  bind(LARGE_LOOP2);
+    // consider a1 to be 16-byte aligned, and a2 is not, but 8-byte-aligned
+    prfm(Address(a1, SoftwarePrefetchHintDistance));
+    prfm(Address(a2, SoftwarePrefetchHintDistance));
+
+    ld1(v0, v1, v2, v3, T2D, Address(post(a1, 8 * wordSize)));
+    ld1(v4, v5, v6, v7, T2D, Address(post(a2, 8 * wordSize)));
+
+    umov(tmp1, v0, D, 0);
+    umov(tmp3, v4, D, 0);
+    umov(tmp2, v0, D, 1);
+    umov(tmp4, v4, D, 1);
+    eor(tmp1, tmp1, tmp5);
+    cbnz(tmp1, LOOP_EXIT);
+    eor(tmp2, tmp2, tmp3);
+    cbnz(tmp2, LOOP_EXIT);
+    umov(tmp1, v1, D, 0);
+    umov(tmp3, v5, D, 0);
+    umov(tmp2, v1, D, 1);
+    umov(tmp5, v5, D, 1);
+    eor(tmp1, tmp1, tmp4);
+    cbnz(tmp1, LOOP_EXIT);
+    eor(tmp2, tmp2, tmp3);
+    cbnz(tmp2, LOOP_EXIT);
+    umov(tmp1, v2, D, 0);
+    umov(tmp3, v6, D, 0);
+    umov(tmp2, v2, D, 1);
+    umov(tmp4, v6, D, 1);
+    eor(tmp1, tmp1, tmp5);
+    cbnz(tmp1, LOOP_EXIT);
+    eor(tmp2, tmp2, tmp3);
+    cbnz(tmp2, LOOP_EXIT);
+    umov(tmp1, v3, D, 0);
+    umov(tmp3, v7, D, 0);
+    umov(tmp2, v3, D, 1);
+    umov(tmp5, v7, D, 1);
+    eor(tmp1, tmp1, tmp4);
+    cbnz(tmp1, LOOP_EXIT);
+    eor(tmp2, tmp2, tmp3);
+    cbnz(tmp2, LOOP_EXIT);
+
+    sub(cnt1, cnt1, 64/elem_size);
+    cmp(cnt1, prefetchThreshold);
+    br(Assembler::GT, LARGE_LOOP2);
+    pop(spilled_regs, sp);
+    b(NEXT_WORD);
+  bind(LOOP_EXIT);
+    pop(spilled_regs, sp);
+    b(DONE);
   // Main 8 byte comparison loop.
   bind(NEXT_WORD); {
     ldr(tmp1, Address(post(a1, wordSize)));
