From 35c9da70316da21a6be2fd92a5e5b5f193bdd9d6 Mon Sep 17 00:00:00 2001
From: Claes Redestad <redestad@openjdk.org>
Date: Wed, 20 Jan 2021 23:45:55 +0000
Subject: [PATCH] 8259498: Reduce overhead of MD5 and SHA digests

Reviewed-by: valeriep
---
 .../security/provider/ByteArrayAccess.java    | 488 +++---------------
 .../classes/sun/security/provider/MD4.java    | 121 +++--
 .../classes/sun/security/provider/MD5.java    | 169 +++---
 .../classes/sun/security/provider/SHA.java    |  24 +-
 .../classes/sun/security/provider/SHA2.java   |  24 +-
 .../classes/sun/security/provider/SHA5.java   |  24 +-
 .../bench/java/security/MessageDigests.java   |  17 +-
 .../openjdk/bench/java/util/UUIDBench.java    |  14 +-
 8 files changed, 305 insertions(+), 576 deletions(-)

diff --git a/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java b/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java
index ea4b77535b2..2fda4ba2d81 100644
--- a/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java
+++ b/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2021, 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
@@ -25,24 +25,14 @@
 
 package sun.security.provider;
 
-import static java.lang.Integer.reverseBytes;
-import static java.lang.Long.reverseBytes;
-
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
 import java.nio.ByteOrder;
 
-import jdk.internal.misc.Unsafe;
-
 /**
  * Optimized methods for converting between byte[] and int[]/long[], both for
  * big endian and little endian byte orders.
  *
- * Currently, it includes a default code path plus two optimized code paths.
- * One is for little endian architectures that support full speed int/long
- * access at unaligned addresses (i.e. x86/amd64). The second is for big endian
- * architectures (that only support correctly aligned access), such as SPARC.
- * These are the only platforms we currently support, but other optimized
- * variants could be added as needed.
- *
  * NOTE that ArrayIndexOutOfBoundsException will be thrown if the bounds checks
  * failed.
  *
@@ -59,408 +49,128 @@ final class ByteArrayAccess {
         // empty
     }
 
-    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    static final class LE {
+        static final VarHandle INT_ARRAY
+                = MethodHandles.byteArrayViewVarHandle(int[].class,
+                ByteOrder.LITTLE_ENDIAN).withInvokeExactBehavior();
 
-    // whether to use the optimized path for little endian platforms that
-    // support full speed unaligned memory access.
-    private static final boolean littleEndianUnaligned;
-
-    // whether to use the optimzied path for big endian platforms that
-    // support only correctly aligned full speed memory access.
-    // (Note that on SPARC unaligned memory access is possible, but it is
-    // implemented using a software trap and therefore very slow)
-    private static final boolean bigEndian;
-
-    private static final int byteArrayOfs = unsafe.arrayBaseOffset(byte[].class);
-
-    static {
-        boolean scaleOK = ((unsafe.arrayIndexScale(byte[].class) == 1)
-            && (unsafe.arrayIndexScale(int[].class) == 4)
-            && (unsafe.arrayIndexScale(long[].class) == 8)
-            && ((byteArrayOfs & 3) == 0));
-
-        ByteOrder byteOrder = ByteOrder.nativeOrder();
-        littleEndianUnaligned =
-            scaleOK && unaligned() && (byteOrder == ByteOrder.LITTLE_ENDIAN);
-        bigEndian =
-            scaleOK && (byteOrder == ByteOrder.BIG_ENDIAN);
+        static final VarHandle LONG_ARRAY
+                = MethodHandles.byteArrayViewVarHandle(long[].class,
+                ByteOrder.LITTLE_ENDIAN).withInvokeExactBehavior();
     }
 
-    // Return whether this platform supports full speed int/long memory access
-    // at unaligned addresses.
-    private static boolean unaligned() {
-        return unsafe.unalignedAccess();
-    }
+    static final class BE {
+        static final VarHandle INT_ARRAY
+                = MethodHandles.byteArrayViewVarHandle(int[].class,
+                ByteOrder.BIG_ENDIAN).withInvokeExactBehavior();
 
-    /**
-     * byte[] to int[] conversion, little endian byte order.
-     */
-    static void b2iLittle(byte[] in, int inOfs, int[] out, int outOfs, int len) {
-        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
-            (outOfs < 0) || ((out.length - outOfs) < len/4)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            inOfs += byteArrayOfs;
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = unsafe.getInt(in, (long)inOfs);
-                inOfs += 4;
-            }
-        } else if (bigEndian && ((inOfs & 3) == 0)) {
-            inOfs += byteArrayOfs;
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));
-                inOfs += 4;
-            }
-        } else {
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = ((in[inOfs    ] & 0xff)      )
-                              | ((in[inOfs + 1] & 0xff) <<  8)
-                              | ((in[inOfs + 2] & 0xff) << 16)
-                              | ((in[inOfs + 3]       ) << 24);
-                inOfs += 4;
-            }
-        }
-    }
-
-    // Special optimization of b2iLittle(in, inOfs, out, 0, 64)
-    static void b2iLittle64(byte[] in, int inOfs, int[] out) {
-        if ((inOfs < 0) || ((in.length - inOfs) < 64) ||
-            (out.length < 16)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            inOfs += byteArrayOfs;
-            out[ 0] = unsafe.getInt(in, (long)(inOfs     ));
-            out[ 1] = unsafe.getInt(in, (long)(inOfs +  4));
-            out[ 2] = unsafe.getInt(in, (long)(inOfs +  8));
-            out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));
-            out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));
-            out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));
-            out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));
-            out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));
-            out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));
-            out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));
-            out[10] = unsafe.getInt(in, (long)(inOfs + 40));
-            out[11] = unsafe.getInt(in, (long)(inOfs + 44));
-            out[12] = unsafe.getInt(in, (long)(inOfs + 48));
-            out[13] = unsafe.getInt(in, (long)(inOfs + 52));
-            out[14] = unsafe.getInt(in, (long)(inOfs + 56));
-            out[15] = unsafe.getInt(in, (long)(inOfs + 60));
-        } else if (bigEndian && ((inOfs & 3) == 0)) {
-            inOfs += byteArrayOfs;
-            out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs     )));
-            out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs +  4)));
-            out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs +  8)));
-            out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));
-            out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));
-            out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));
-            out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));
-            out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));
-            out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));
-            out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));
-            out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));
-            out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));
-            out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));
-            out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));
-            out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));
-            out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));
-        } else {
-            b2iLittle(in, inOfs, out, 0, 64);
-        }
+        static final VarHandle LONG_ARRAY
+                = MethodHandles.byteArrayViewVarHandle(long[].class,
+                ByteOrder.BIG_ENDIAN).withInvokeExactBehavior();
     }
 
     /**
      * int[] to byte[] conversion, little endian byte order.
      */
     static void i2bLittle(int[] in, int inOfs, byte[] out, int outOfs, int len) {
-        if ((inOfs < 0) || ((in.length - inOfs) < len/4) ||
-            (outOfs < 0) || ((out.length - outOfs) < len)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            outOfs += byteArrayOfs;
-            len += outOfs;
-            while (outOfs < len) {
-                unsafe.putInt(out, (long)outOfs, in[inOfs++]);
-                outOfs += 4;
-            }
-        } else if (bigEndian && ((outOfs & 3) == 0)) {
-            outOfs += byteArrayOfs;
-            len += outOfs;
-            while (outOfs < len) {
-                unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));
-                outOfs += 4;
-            }
-        } else {
-            len += outOfs;
-            while (outOfs < len) {
-                int i = in[inOfs++];
-                out[outOfs++] = (byte)(i      );
-                out[outOfs++] = (byte)(i >>  8);
-                out[outOfs++] = (byte)(i >> 16);
-                out[outOfs++] = (byte)(i >> 24);
-            }
+        len += outOfs;
+        while (outOfs < len) {
+            LE.INT_ARRAY.set(out, outOfs, in[inOfs++]);
+            outOfs += 4;
         }
     }
 
     // Store one 32-bit value into out[outOfs..outOfs+3] in little endian order.
     static void i2bLittle4(int val, byte[] out, int outOfs) {
-        if ((outOfs < 0) || ((out.length - outOfs) < 4)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);
-        } else if (bigEndian && ((outOfs & 3) == 0)) {
-            unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));
-        } else {
-            out[outOfs    ] = (byte)(val      );
-            out[outOfs + 1] = (byte)(val >>  8);
-            out[outOfs + 2] = (byte)(val >> 16);
-            out[outOfs + 3] = (byte)(val >> 24);
-        }
+        LE.INT_ARRAY.set(out, outOfs, val);
     }
 
     /**
      * byte[] to int[] conversion, big endian byte order.
      */
     static void b2iBig(byte[] in, int inOfs, int[] out, int outOfs, int len) {
-        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
-            (outOfs < 0) || ((out.length - outOfs) < len/4)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            inOfs += byteArrayOfs;
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));
-                inOfs += 4;
-            }
-        } else if (bigEndian && ((inOfs & 3) == 0)) {
-            inOfs += byteArrayOfs;
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = unsafe.getInt(in, (long)inOfs);
-                inOfs += 4;
-            }
-        } else {
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = ((in[inOfs + 3] & 0xff)      )
-                              | ((in[inOfs + 2] & 0xff) <<  8)
-                              | ((in[inOfs + 1] & 0xff) << 16)
-                              | ((in[inOfs    ]       ) << 24);
-                inOfs += 4;
-            }
+        len += inOfs;
+        while (inOfs < len) {
+            out[outOfs++] = (int) BE.INT_ARRAY.get(in, inOfs);
+            inOfs += 4;
         }
     }
 
     // Special optimization of b2iBig(in, inOfs, out, 0, 64)
     static void b2iBig64(byte[] in, int inOfs, int[] out) {
-        if ((inOfs < 0) || ((in.length - inOfs) < 64) ||
-            (out.length < 16)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            inOfs += byteArrayOfs;
-            out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs     )));
-            out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs +  4)));
-            out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs +  8)));
-            out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));
-            out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));
-            out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));
-            out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));
-            out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));
-            out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));
-            out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));
-            out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));
-            out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));
-            out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));
-            out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));
-            out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));
-            out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));
-        } else if (bigEndian && ((inOfs & 3) == 0)) {
-            inOfs += byteArrayOfs;
-            out[ 0] = unsafe.getInt(in, (long)(inOfs     ));
-            out[ 1] = unsafe.getInt(in, (long)(inOfs +  4));
-            out[ 2] = unsafe.getInt(in, (long)(inOfs +  8));
-            out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));
-            out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));
-            out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));
-            out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));
-            out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));
-            out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));
-            out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));
-            out[10] = unsafe.getInt(in, (long)(inOfs + 40));
-            out[11] = unsafe.getInt(in, (long)(inOfs + 44));
-            out[12] = unsafe.getInt(in, (long)(inOfs + 48));
-            out[13] = unsafe.getInt(in, (long)(inOfs + 52));
-            out[14] = unsafe.getInt(in, (long)(inOfs + 56));
-            out[15] = unsafe.getInt(in, (long)(inOfs + 60));
-        } else {
-            b2iBig(in, inOfs, out, 0, 64);
-        }
+        out[ 0] = (int) BE.INT_ARRAY.get(in, inOfs     );
+        out[ 1] = (int) BE.INT_ARRAY.get(in, inOfs +  4);
+        out[ 2] = (int) BE.INT_ARRAY.get(in, inOfs +  8);
+        out[ 3] = (int) BE.INT_ARRAY.get(in, inOfs + 12);
+        out[ 4] = (int) BE.INT_ARRAY.get(in, inOfs + 16);
+        out[ 5] = (int) BE.INT_ARRAY.get(in, inOfs + 20);
+        out[ 6] = (int) BE.INT_ARRAY.get(in, inOfs + 24);
+        out[ 7] = (int) BE.INT_ARRAY.get(in, inOfs + 28);
+        out[ 8] = (int) BE.INT_ARRAY.get(in, inOfs + 32);
+        out[ 9] = (int) BE.INT_ARRAY.get(in, inOfs + 36);
+        out[10] = (int) BE.INT_ARRAY.get(in, inOfs + 40);
+        out[11] = (int) BE.INT_ARRAY.get(in, inOfs + 44);
+        out[12] = (int) BE.INT_ARRAY.get(in, inOfs + 48);
+        out[13] = (int) BE.INT_ARRAY.get(in, inOfs + 52);
+        out[14] = (int) BE.INT_ARRAY.get(in, inOfs + 56);
+        out[15] = (int) BE.INT_ARRAY.get(in, inOfs + 60);
     }
 
     /**
      * int[] to byte[] conversion, big endian byte order.
      */
     static void i2bBig(int[] in, int inOfs, byte[] out, int outOfs, int len) {
-        if ((inOfs < 0) || ((in.length - inOfs) < len/4) ||
-            (outOfs < 0) || ((out.length - outOfs) < len)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            outOfs += byteArrayOfs;
-            len += outOfs;
-            while (outOfs < len) {
-                unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));
-                outOfs += 4;
-            }
-        } else if (bigEndian && ((outOfs & 3) == 0)) {
-            outOfs += byteArrayOfs;
-            len += outOfs;
-            while (outOfs < len) {
-                unsafe.putInt(out, (long)outOfs, in[inOfs++]);
-                outOfs += 4;
-            }
-        } else {
-            len += outOfs;
-            while (outOfs < len) {
-                int i = in[inOfs++];
-                out[outOfs++] = (byte)(i >> 24);
-                out[outOfs++] = (byte)(i >> 16);
-                out[outOfs++] = (byte)(i >>  8);
-                out[outOfs++] = (byte)(i      );
-            }
+        len += outOfs;
+        while (outOfs < len) {
+            BE.INT_ARRAY.set(out, outOfs, in[inOfs++]);
+            outOfs += 4;
         }
     }
 
     // Store one 32-bit value into out[outOfs..outOfs+3] in big endian order.
     static void i2bBig4(int val, byte[] out, int outOfs) {
-        if ((outOfs < 0) || ((out.length - outOfs) < 4)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));
-        } else if (bigEndian && ((outOfs & 3) == 0)) {
-            unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);
-        } else {
-            out[outOfs    ] = (byte)(val >> 24);
-            out[outOfs + 1] = (byte)(val >> 16);
-            out[outOfs + 2] = (byte)(val >>  8);
-            out[outOfs + 3] = (byte)(val      );
-        }
+        BE.INT_ARRAY.set(out, outOfs, val);
     }
 
     /**
      * byte[] to long[] conversion, big endian byte order.
      */
     static void b2lBig(byte[] in, int inOfs, long[] out, int outOfs, int len) {
-        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
-            (outOfs < 0) || ((out.length - outOfs) < len/8)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            inOfs += byteArrayOfs;
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = reverseBytes(unsafe.getLong(in, (long)inOfs));
-                inOfs += 8;
-            }
-        } else if (bigEndian && ((inOfs & 3) == 0)) {
-            // In the current HotSpot memory layout, the first element of a
-            // byte[] is only 32-bit aligned, not 64-bit.
-            // That means we could use getLong() only for offset 4, 12, etc.,
-            // which would rarely occur in practice. Instead, we use an
-            // optimization that uses getInt() so that it works for offset 0.
-            inOfs += byteArrayOfs;
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] =
-                      ((long)unsafe.getInt(in, (long)inOfs) << 32)
-                          | (unsafe.getInt(in, (long)(inOfs + 4)) & 0xffffffffL);
-                inOfs += 8;
-            }
-        } else {
-            len += inOfs;
-            while (inOfs < len) {
-                int i1 = ((in[inOfs + 3] & 0xff)      )
-                       | ((in[inOfs + 2] & 0xff) <<  8)
-                       | ((in[inOfs + 1] & 0xff) << 16)
-                       | ((in[inOfs    ]       ) << 24);
-                inOfs += 4;
-                int i2 = ((in[inOfs + 3] & 0xff)      )
-                       | ((in[inOfs + 2] & 0xff) <<  8)
-                       | ((in[inOfs + 1] & 0xff) << 16)
-                       | ((in[inOfs    ]       ) << 24);
-                out[outOfs++] = ((long)i1 << 32) | (i2 & 0xffffffffL);
-                inOfs += 4;
-            }
+        len += inOfs;
+        while (inOfs < len) {
+            out[outOfs++] = (long) BE.LONG_ARRAY.get(in, inOfs);
+            inOfs += 8;
         }
     }
 
     // Special optimization of b2lBig(in, inOfs, out, 0, 128)
     static void b2lBig128(byte[] in, int inOfs, long[] out) {
-        if ((inOfs < 0) || ((in.length - inOfs) < 128) ||
-            (out.length < 16)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            inOfs += byteArrayOfs;
-            out[ 0] = reverseBytes(unsafe.getLong(in, (long)(inOfs      )));
-            out[ 1] = reverseBytes(unsafe.getLong(in, (long)(inOfs +   8)));
-            out[ 2] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  16)));
-            out[ 3] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  24)));
-            out[ 4] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  32)));
-            out[ 5] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  40)));
-            out[ 6] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  48)));
-            out[ 7] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  56)));
-            out[ 8] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  64)));
-            out[ 9] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  72)));
-            out[10] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  80)));
-            out[11] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  88)));
-            out[12] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  96)));
-            out[13] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 104)));
-            out[14] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 112)));
-            out[15] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 120)));
-        } else {
-            // no optimization for big endian, see comments in b2lBig
-            b2lBig(in, inOfs, out, 0, 128);
-        }
+        out[ 0] = (long) BE.LONG_ARRAY.get(in, inOfs      );
+        out[ 1] = (long) BE.LONG_ARRAY.get(in, inOfs +   8);
+        out[ 2] = (long) BE.LONG_ARRAY.get(in, inOfs +  16);
+        out[ 3] = (long) BE.LONG_ARRAY.get(in, inOfs +  24);
+        out[ 4] = (long) BE.LONG_ARRAY.get(in, inOfs +  32);
+        out[ 5] = (long) BE.LONG_ARRAY.get(in, inOfs +  40);
+        out[ 6] = (long) BE.LONG_ARRAY.get(in, inOfs +  48);
+        out[ 7] = (long) BE.LONG_ARRAY.get(in, inOfs +  56);
+        out[ 8] = (long) BE.LONG_ARRAY.get(in, inOfs +  64);
+        out[ 9] = (long) BE.LONG_ARRAY.get(in, inOfs +  72);
+        out[10] = (long) BE.LONG_ARRAY.get(in, inOfs +  80);
+        out[11] = (long) BE.LONG_ARRAY.get(in, inOfs +  88);
+        out[12] = (long) BE.LONG_ARRAY.get(in, inOfs +  96);
+        out[13] = (long) BE.LONG_ARRAY.get(in, inOfs + 104);
+        out[14] = (long) BE.LONG_ARRAY.get(in, inOfs + 112);
+        out[15] = (long) BE.LONG_ARRAY.get(in, inOfs + 120);
     }
 
     /**
      * long[] to byte[] conversion, big endian byte order.
      */
     static void l2bBig(long[] in, int inOfs, byte[] out, int outOfs, int len) {
-        if ((inOfs < 0) || ((in.length - inOfs) < len/8) ||
-            (outOfs < 0) || ((out.length - outOfs) < len)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            outOfs += byteArrayOfs;
-            len += outOfs;
-            while (outOfs < len) {
-                unsafe.putLong(out, (long)outOfs, reverseBytes(in[inOfs++]));
-                outOfs += 8;
-            }
-        } else {
-            len += outOfs;
-            while (outOfs < len) {
-                long i = in[inOfs++];
-                out[outOfs++] = (byte)(i >> 56);
-                out[outOfs++] = (byte)(i >> 48);
-                out[outOfs++] = (byte)(i >> 40);
-                out[outOfs++] = (byte)(i >> 32);
-                out[outOfs++] = (byte)(i >> 24);
-                out[outOfs++] = (byte)(i >> 16);
-                out[outOfs++] = (byte)(i >>  8);
-                out[outOfs++] = (byte)(i      );
-            }
+        len += outOfs;
+        while (outOfs < len) {
+            BE.LONG_ARRAY.set(out, outOfs, in[inOfs++]);
+            outOfs += 8;
         }
     }
 
@@ -468,30 +178,10 @@ final class ByteArrayAccess {
      * byte[] to long[] conversion, little endian byte order
      */
     static void b2lLittle(byte[] in, int inOfs, long[] out, int outOfs, int len) {
-        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
-            ((outOfs < 0) || (out.length - outOfs) < len/8)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            inOfs += byteArrayOfs;
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = unsafe.getLong(in, (long)inOfs);
-                inOfs += 8;
-            }
-       } else {
-            len += inOfs;
-            while (inOfs < len) {
-                out[outOfs++] = ((in[inOfs    ] & 0xffL)
-                   | ((in[inOfs + 1] & 0xffL) <<  8)
-                   | ((in[inOfs + 2] & 0xffL) << 16)
-                   | ((in[inOfs + 3] & 0xffL) << 24)
-                   | ((in[inOfs + 4] & 0xffL) << 32)
-                   | ((in[inOfs + 5] & 0xffL) << 40)
-                   | ((in[inOfs + 6] & 0xffL) << 48)
-                   | ((in[inOfs + 7] & 0xffL) << 56));
-                inOfs += 8;
-            }
+        len += inOfs;
+        while (inOfs < len) {
+            out[outOfs++] = (long) LE.LONG_ARRAY.get(in, inOfs);
+            inOfs += 8;
         }
     }
 
@@ -500,30 +190,10 @@ final class ByteArrayAccess {
      * long[] to byte[] conversion, little endian byte order
      */
     static void l2bLittle(long[] in, int inOfs, byte[] out, int outOfs, int len) {
-        if ((inOfs < 0) || ((in.length - inOfs) < len/8) ||
-            (outOfs < 0) || ((out.length - outOfs) < len)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        if (littleEndianUnaligned) {
-            outOfs += byteArrayOfs;
-            len += outOfs;
-            while (outOfs < len) {
-                unsafe.putLong(out, (long)outOfs, in[inOfs++]);
-                outOfs += 8;
-            }
-        } else {
-            len += outOfs;
-            while (outOfs < len) {
-                long i = in[inOfs++];
-                out[outOfs++] = (byte)(i      );
-                out[outOfs++] = (byte)(i >>  8);
-                out[outOfs++] = (byte)(i >> 16);
-                out[outOfs++] = (byte)(i >> 24);
-                out[outOfs++] = (byte)(i >> 32);
-                out[outOfs++] = (byte)(i >> 40);
-                out[outOfs++] = (byte)(i >> 48);
-                out[outOfs++] = (byte)(i >> 56);
-            }
+        len += outOfs;
+        while (outOfs < len) {
+            LE.LONG_ARRAY.set(out, outOfs, in[inOfs++]);
+            outOfs += 8;
         }
     }
 }
diff --git a/src/java.base/share/classes/sun/security/provider/MD4.java b/src/java.base/share/classes/sun/security/provider/MD4.java
index 92c6df01c6b..ebb51d7746b 100644
--- a/src/java.base/share/classes/sun/security/provider/MD4.java
+++ b/src/java.base/share/classes/sun/security/provider/MD4.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2021, 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
@@ -47,8 +47,6 @@ public final class MD4 extends DigestBase {
 
     // state of this object
     private int[] state;
-    // temporary buffer, used by implCompress()
-    private int[] x;
 
     // rotation constants
     private static final int S11 = 3;
@@ -93,7 +91,6 @@ public final class MD4 extends DigestBase {
     public MD4() {
         super("MD4", 16, 64);
         state = new int[4];
-        x = new int[16];
         resetHashes();
     }
 
@@ -101,7 +98,6 @@ public final class MD4 extends DigestBase {
     public Object clone() throws CloneNotSupportedException {
         MD4 copy = (MD4) super.clone();
         copy.state = copy.state.clone();
-        copy.x = new int[16];
         return copy;
     }
 
@@ -111,8 +107,6 @@ public final class MD4 extends DigestBase {
     void implReset() {
         // Load magic initialization constants.
         resetHashes();
-        // clear out old data
-        Arrays.fill(x, 0);
     }
 
     private void resetHashes() {
@@ -162,7 +156,22 @@ public final class MD4 extends DigestBase {
      * bytes from the buffer, beginning at the specified offset.
      */
     void implCompress(byte[] buf, int ofs) {
-        b2iLittle64(buf, ofs, x);
+        int x0 = (int) LE.INT_ARRAY.get(buf, ofs);
+        int x1 = (int) LE.INT_ARRAY.get(buf, ofs + 4);
+        int x2 = (int) LE.INT_ARRAY.get(buf, ofs + 8);
+        int x3 = (int) LE.INT_ARRAY.get(buf, ofs + 12);
+        int x4 = (int) LE.INT_ARRAY.get(buf, ofs + 16);
+        int x5 = (int) LE.INT_ARRAY.get(buf, ofs + 20);
+        int x6 = (int) LE.INT_ARRAY.get(buf, ofs + 24);
+        int x7 = (int) LE.INT_ARRAY.get(buf, ofs + 28);
+        int x8 = (int) LE.INT_ARRAY.get(buf, ofs + 32);
+        int x9 = (int) LE.INT_ARRAY.get(buf, ofs + 36);
+        int x10 = (int) LE.INT_ARRAY.get(buf, ofs + 40);
+        int x11 = (int) LE.INT_ARRAY.get(buf, ofs + 44);
+        int x12 = (int) LE.INT_ARRAY.get(buf, ofs + 48);
+        int x13 = (int) LE.INT_ARRAY.get(buf, ofs + 52);
+        int x14 = (int) LE.INT_ARRAY.get(buf, ofs + 56);
+        int x15 = (int) LE.INT_ARRAY.get(buf, ofs + 60);
 
         int a = state[0];
         int b = state[1];
@@ -170,58 +179,58 @@ public final class MD4 extends DigestBase {
         int d = state[3];
 
         /* Round 1 */
-        a = FF (a, b, c, d, x[ 0], S11); /* 1 */
-        d = FF (d, a, b, c, x[ 1], S12); /* 2 */
-        c = FF (c, d, a, b, x[ 2], S13); /* 3 */
-        b = FF (b, c, d, a, x[ 3], S14); /* 4 */
-        a = FF (a, b, c, d, x[ 4], S11); /* 5 */
-        d = FF (d, a, b, c, x[ 5], S12); /* 6 */
-        c = FF (c, d, a, b, x[ 6], S13); /* 7 */
-        b = FF (b, c, d, a, x[ 7], S14); /* 8 */
-        a = FF (a, b, c, d, x[ 8], S11); /* 9 */
-        d = FF (d, a, b, c, x[ 9], S12); /* 10 */
-        c = FF (c, d, a, b, x[10], S13); /* 11 */
-        b = FF (b, c, d, a, x[11], S14); /* 12 */
-        a = FF (a, b, c, d, x[12], S11); /* 13 */
-        d = FF (d, a, b, c, x[13], S12); /* 14 */
-        c = FF (c, d, a, b, x[14], S13); /* 15 */
-        b = FF (b, c, d, a, x[15], S14); /* 16 */
+        a = FF (a, b, c, d, x0,  S11); /* 1 */
+        d = FF (d, a, b, c, x1,  S12); /* 2 */
+        c = FF (c, d, a, b, x2,  S13); /* 3 */
+        b = FF (b, c, d, a, x3,  S14); /* 4 */
+        a = FF (a, b, c, d, x4,  S11); /* 5 */
+        d = FF (d, a, b, c, x5,  S12); /* 6 */
+        c = FF (c, d, a, b, x6,  S13); /* 7 */
+        b = FF (b, c, d, a, x7,  S14); /* 8 */
+        a = FF (a, b, c, d, x8,  S11); /* 9 */
+        d = FF (d, a, b, c, x9,  S12); /* 10 */
+        c = FF (c, d, a, b, x10, S13); /* 11 */
+        b = FF (b, c, d, a, x11, S14); /* 12 */
+        a = FF (a, b, c, d, x12, S11); /* 13 */
+        d = FF (d, a, b, c, x13, S12); /* 14 */
+        c = FF (c, d, a, b, x14, S13); /* 15 */
+        b = FF (b, c, d, a, x15, S14); /* 16 */
 
         /* Round 2 */
-        a = GG (a, b, c, d, x[ 0], S21); /* 17 */
-        d = GG (d, a, b, c, x[ 4], S22); /* 18 */
-        c = GG (c, d, a, b, x[ 8], S23); /* 19 */
-        b = GG (b, c, d, a, x[12], S24); /* 20 */
-        a = GG (a, b, c, d, x[ 1], S21); /* 21 */
-        d = GG (d, a, b, c, x[ 5], S22); /* 22 */
-        c = GG (c, d, a, b, x[ 9], S23); /* 23 */
-        b = GG (b, c, d, a, x[13], S24); /* 24 */
-        a = GG (a, b, c, d, x[ 2], S21); /* 25 */
-        d = GG (d, a, b, c, x[ 6], S22); /* 26 */
-        c = GG (c, d, a, b, x[10], S23); /* 27 */
-        b = GG (b, c, d, a, x[14], S24); /* 28 */
-        a = GG (a, b, c, d, x[ 3], S21); /* 29 */
-        d = GG (d, a, b, c, x[ 7], S22); /* 30 */
-        c = GG (c, d, a, b, x[11], S23); /* 31 */
-        b = GG (b, c, d, a, x[15], S24); /* 32 */
+        a = GG (a, b, c, d, x0,  S21); /* 17 */
+        d = GG (d, a, b, c, x4,  S22); /* 18 */
+        c = GG (c, d, a, b, x8,  S23); /* 19 */
+        b = GG (b, c, d, a, x12, S24); /* 20 */
+        a = GG (a, b, c, d, x1,  S21); /* 21 */
+        d = GG (d, a, b, c, x5,  S22); /* 22 */
+        c = GG (c, d, a, b, x9,  S23); /* 23 */
+        b = GG (b, c, d, a, x13, S24); /* 24 */
+        a = GG (a, b, c, d, x2,  S21); /* 25 */
+        d = GG (d, a, b, c, x6,  S22); /* 26 */
+        c = GG (c, d, a, b, x10, S23); /* 27 */
+        b = GG (b, c, d, a, x14, S24); /* 28 */
+        a = GG (a, b, c, d, x3,  S21); /* 29 */
+        d = GG (d, a, b, c, x7,  S22); /* 30 */
+        c = GG (c, d, a, b, x11, S23); /* 31 */
+        b = GG (b, c, d, a, x15, S24); /* 32 */
 
         /* Round 3 */
-        a = HH (a, b, c, d, x[ 0], S31); /* 33 */
-        d = HH (d, a, b, c, x[ 8], S32); /* 34 */
-        c = HH (c, d, a, b, x[ 4], S33); /* 35 */
-        b = HH (b, c, d, a, x[12], S34); /* 36 */
-        a = HH (a, b, c, d, x[ 2], S31); /* 37 */
-        d = HH (d, a, b, c, x[10], S32); /* 38 */
-        c = HH (c, d, a, b, x[ 6], S33); /* 39 */
-        b = HH (b, c, d, a, x[14], S34); /* 40 */
-        a = HH (a, b, c, d, x[ 1], S31); /* 41 */
-        d = HH (d, a, b, c, x[ 9], S32); /* 42 */
-        c = HH (c, d, a, b, x[ 5], S33); /* 43 */
-        b = HH (b, c, d, a, x[13], S34); /* 44 */
-        a = HH (a, b, c, d, x[ 3], S31); /* 45 */
-        d = HH (d, a, b, c, x[11], S32); /* 46 */
-        c = HH (c, d, a, b, x[ 7], S33); /* 47 */
-        b = HH (b, c, d, a, x[15], S34); /* 48 */
+        a = HH (a, b, c, d, x0,  S31); /* 33 */
+        d = HH (d, a, b, c, x8,  S32); /* 34 */
+        c = HH (c, d, a, b, x4,  S33); /* 35 */
+        b = HH (b, c, d, a, x12, S34); /* 36 */
+        a = HH (a, b, c, d, x2,  S31); /* 37 */
+        d = HH (d, a, b, c, x10, S32); /* 38 */
+        c = HH (c, d, a, b, x6,  S33); /* 39 */
+        b = HH (b, c, d, a, x14, S34); /* 40 */
+        a = HH (a, b, c, d, x1,  S31); /* 41 */
+        d = HH (d, a, b, c, x9,  S32); /* 42 */
+        c = HH (c, d, a, b, x5,  S33); /* 43 */
+        b = HH (b, c, d, a, x13, S34); /* 44 */
+        a = HH (a, b, c, d, x3,  S31); /* 45 */
+        d = HH (d, a, b, c, x11, S32); /* 46 */
+        c = HH (c, d, a, b, x7,  S33); /* 47 */
+        b = HH (b, c, d, a, x15, S34); /* 48 */
 
         state[0] += a;
         state[1] += b;
diff --git a/src/java.base/share/classes/sun/security/provider/MD5.java b/src/java.base/share/classes/sun/security/provider/MD5.java
index ca480e8de10..941a2c00792 100644
--- a/src/java.base/share/classes/sun/security/provider/MD5.java
+++ b/src/java.base/share/classes/sun/security/provider/MD5.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2021, 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
@@ -25,6 +25,9 @@
 
 package sun.security.provider;
 
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.nio.ByteOrder;
 import java.util.Arrays;
 import java.util.Objects;
 
@@ -44,8 +47,6 @@ public final class MD5 extends DigestBase {
 
     // state of this object
     private int[] state;
-    // temporary buffer, used by implCompress()
-    private int[] x;
 
     // rotation constants
     private static final int S11 = 7;
@@ -69,15 +70,13 @@ public final class MD5 extends DigestBase {
     public MD5() {
         super("MD5", 16, 64);
         state = new int[4];
-        x = new int[16];
-        resetHashes();
+        implReset();
     }
 
     // clone this object
     public Object clone() throws CloneNotSupportedException {
         MD5 copy = (MD5) super.clone();
         copy.state = copy.state.clone();
-        copy.x = new int[16];
         return copy;
     }
 
@@ -86,12 +85,6 @@ public final class MD5 extends DigestBase {
      */
     void implReset() {
         // Load magic initialization constants.
-        resetHashes();
-        // clear out old data
-        Arrays.fill(x, 0);
-    }
-
-    private void resetHashes() {
         state[0] = 0x67452301;
         state[1] = 0xefcdab89;
         state[2] = 0x98badcfe;
@@ -156,11 +149,12 @@ public final class MD5 extends DigestBase {
     private void implCompressCheck(byte[] buf, int ofs) {
         Objects.requireNonNull(buf);
 
-        // The checks performed by the method 'b2iBig64'
-        // are sufficient for the case when the method
+        // These checks are sufficient for the case when the method
         // 'implCompressImpl' is replaced with a compiler
         // intrinsic.
-        b2iLittle64(buf, ofs, x);
+        if ((ofs < 0) || ((buf.length - ofs) < 64)) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
     }
 
     // The method 'implCompress0 seems not to use its parameters.
@@ -175,77 +169,94 @@ public final class MD5 extends DigestBase {
         int c = state[2];
         int d = state[3];
 
+        int x0 = (int) LE.INT_ARRAY.get(buf, ofs);
+        int x1 = (int) LE.INT_ARRAY.get(buf, ofs + 4);
+        int x2 = (int) LE.INT_ARRAY.get(buf, ofs + 8);
+        int x3 = (int) LE.INT_ARRAY.get(buf, ofs + 12);
+        int x4 = (int) LE.INT_ARRAY.get(buf, ofs + 16);
+        int x5 = (int) LE.INT_ARRAY.get(buf, ofs + 20);
+        int x6 = (int) LE.INT_ARRAY.get(buf, ofs + 24);
+        int x7 = (int) LE.INT_ARRAY.get(buf, ofs + 28);
+        int x8 = (int) LE.INT_ARRAY.get(buf, ofs + 32);
+        int x9 = (int) LE.INT_ARRAY.get(buf, ofs + 36);
+        int x10 = (int) LE.INT_ARRAY.get(buf, ofs + 40);
+        int x11 = (int) LE.INT_ARRAY.get(buf, ofs + 44);
+        int x12 = (int) LE.INT_ARRAY.get(buf, ofs + 48);
+        int x13 = (int) LE.INT_ARRAY.get(buf, ofs + 52);
+        int x14 = (int) LE.INT_ARRAY.get(buf, ofs + 56);
+        int x15 = (int) LE.INT_ARRAY.get(buf, ofs + 60);
+
         /* Round 1 */
-        a = FF ( a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
-        d = FF ( d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
-        c = FF ( c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
-        b = FF ( b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
-        a = FF ( a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
-        d = FF ( d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
-        c = FF ( c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
-        b = FF ( b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
-        a = FF ( a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
-        d = FF ( d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
-        c = FF ( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
-        b = FF ( b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
-        a = FF ( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
-        d = FF ( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
-        c = FF ( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
-        b = FF ( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+        a = FF ( a, b, c, d, x0,  S11, 0xd76aa478); /* 1 */
+        d = FF ( d, a, b, c, x1,  S12, 0xe8c7b756); /* 2 */
+        c = FF ( c, d, a, b, x2,  S13, 0x242070db); /* 3 */
+        b = FF ( b, c, d, a, x3,  S14, 0xc1bdceee); /* 4 */
+        a = FF ( a, b, c, d, x4,  S11, 0xf57c0faf); /* 5 */
+        d = FF ( d, a, b, c, x5,  S12, 0x4787c62a); /* 6 */
+        c = FF ( c, d, a, b, x6,  S13, 0xa8304613); /* 7 */
+        b = FF ( b, c, d, a, x7,  S14, 0xfd469501); /* 8 */
+        a = FF ( a, b, c, d, x8,  S11, 0x698098d8); /* 9 */
+        d = FF ( d, a, b, c, x9,  S12, 0x8b44f7af); /* 10 */
+        c = FF ( c, d, a, b, x10, S13, 0xffff5bb1); /* 11 */
+        b = FF ( b, c, d, a, x11, S14, 0x895cd7be); /* 12 */
+        a = FF ( a, b, c, d, x12, S11, 0x6b901122); /* 13 */
+        d = FF ( d, a, b, c, x13, S12, 0xfd987193); /* 14 */
+        c = FF ( c, d, a, b, x14, S13, 0xa679438e); /* 15 */
+        b = FF ( b, c, d, a, x15, S14, 0x49b40821); /* 16 */
 
         /* Round 2 */
-        a = GG ( a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
-        d = GG ( d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
-        c = GG ( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
-        b = GG ( b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
-        a = GG ( a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
-        d = GG ( d, a, b, c, x[10], S22,  0x2441453); /* 22 */
-        c = GG ( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
-        b = GG ( b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
-        a = GG ( a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
-        d = GG ( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
-        c = GG ( c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
-        b = GG ( b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
-        a = GG ( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
-        d = GG ( d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
-        c = GG ( c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
-        b = GG ( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+        a = GG ( a, b, c, d, x1,  S21, 0xf61e2562); /* 17 */
+        d = GG ( d, a, b, c, x6,  S22, 0xc040b340); /* 18 */
+        c = GG ( c, d, a, b, x11, S23, 0x265e5a51); /* 19 */
+        b = GG ( b, c, d, a, x0,  S24, 0xe9b6c7aa); /* 20 */
+        a = GG ( a, b, c, d, x5,  S21, 0xd62f105d); /* 21 */
+        d = GG ( d, a, b, c, x10, S22,  0x2441453); /* 22 */
+        c = GG ( c, d, a, b, x15, S23, 0xd8a1e681); /* 23 */
+        b = GG ( b, c, d, a, x4,  S24, 0xe7d3fbc8); /* 24 */
+        a = GG ( a, b, c, d, x9,  S21, 0x21e1cde6); /* 25 */
+        d = GG ( d, a, b, c, x14, S22, 0xc33707d6); /* 26 */
+        c = GG ( c, d, a, b, x3,  S23, 0xf4d50d87); /* 27 */
+        b = GG ( b, c, d, a, x8,  S24, 0x455a14ed); /* 28 */
+        a = GG ( a, b, c, d, x13, S21, 0xa9e3e905); /* 29 */
+        d = GG ( d, a, b, c, x2,  S22, 0xfcefa3f8); /* 30 */
+        c = GG ( c, d, a, b, x7,  S23, 0x676f02d9); /* 31 */
+        b = GG ( b, c, d, a, x12, S24, 0x8d2a4c8a); /* 32 */
 
         /* Round 3 */
-        a = HH ( a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
-        d = HH ( d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
-        c = HH ( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
-        b = HH ( b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
-        a = HH ( a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
-        d = HH ( d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
-        c = HH ( c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
-        b = HH ( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
-        a = HH ( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
-        d = HH ( d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
-        c = HH ( c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
-        b = HH ( b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
-        a = HH ( a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
-        d = HH ( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
-        c = HH ( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
-        b = HH ( b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+        a = HH ( a, b, c, d, x5,  S31, 0xfffa3942); /* 33 */
+        d = HH ( d, a, b, c, x8,  S32, 0x8771f681); /* 34 */
+        c = HH ( c, d, a, b, x11, S33, 0x6d9d6122); /* 35 */
+        b = HH ( b, c, d, a, x14, S34, 0xfde5380c); /* 36 */
+        a = HH ( a, b, c, d, x1,  S31, 0xa4beea44); /* 37 */
+        d = HH ( d, a, b, c, x4,  S32, 0x4bdecfa9); /* 38 */
+        c = HH ( c, d, a, b, x7,  S33, 0xf6bb4b60); /* 39 */
+        b = HH ( b, c, d, a, x10, S34, 0xbebfbc70); /* 40 */
+        a = HH ( a, b, c, d, x13, S31, 0x289b7ec6); /* 41 */
+        d = HH ( d, a, b, c, x0,  S32, 0xeaa127fa); /* 42 */
+        c = HH ( c, d, a, b, x3,  S33, 0xd4ef3085); /* 43 */
+        b = HH ( b, c, d, a, x6,  S34,  0x4881d05); /* 44 */
+        a = HH ( a, b, c, d, x9,  S31, 0xd9d4d039); /* 45 */
+        d = HH ( d, a, b, c, x12, S32, 0xe6db99e5); /* 46 */
+        c = HH ( c, d, a, b, x15, S33, 0x1fa27cf8); /* 47 */
+        b = HH ( b, c, d, a, x2,  S34, 0xc4ac5665); /* 48 */
 
         /* Round 4 */
-        a = II ( a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
-        d = II ( d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
-        c = II ( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
-        b = II ( b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
-        a = II ( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
-        d = II ( d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
-        c = II ( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
-        b = II ( b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
-        a = II ( a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
-        d = II ( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
-        c = II ( c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
-        b = II ( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
-        a = II ( a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
-        d = II ( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
-        c = II ( c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
-        b = II ( b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+        a = II ( a, b, c, d, x0,  S41, 0xf4292244); /* 49 */
+        d = II ( d, a, b, c, x7,  S42, 0x432aff97); /* 50 */
+        c = II ( c, d, a, b, x14, S43, 0xab9423a7); /* 51 */
+        b = II ( b, c, d, a, x5,  S44, 0xfc93a039); /* 52 */
+        a = II ( a, b, c, d, x12, S41, 0x655b59c3); /* 53 */
+        d = II ( d, a, b, c, x3,  S42, 0x8f0ccc92); /* 54 */
+        c = II ( c, d, a, b, x10, S43, 0xffeff47d); /* 55 */
+        b = II ( b, c, d, a, x1,  S44, 0x85845dd1); /* 56 */
+        a = II ( a, b, c, d, x8,  S41, 0x6fa87e4f); /* 57 */
+        d = II ( d, a, b, c, x15, S42, 0xfe2ce6e0); /* 58 */
+        c = II ( c, d, a, b, x6,  S43, 0xa3014314); /* 59 */
+        b = II ( b, c, d, a, x13, S44, 0x4e0811a1); /* 60 */
+        a = II ( a, b, c, d, x4,  S41, 0xf7537e82); /* 61 */
+        d = II ( d, a, b, c, x11, S42, 0xbd3af235); /* 62 */
+        c = II ( c, d, a, b, x2,  S43, 0x2ad7d2bb); /* 63 */
+        b = II ( b, c, d, a, x9,  S44, 0xeb86d391); /* 64 */
 
         state[0] += a;
         state[1] += b;
diff --git a/src/java.base/share/classes/sun/security/provider/SHA.java b/src/java.base/share/classes/sun/security/provider/SHA.java
index 886eddac569..94958b3c334 100644
--- a/src/java.base/share/classes/sun/security/provider/SHA.java
+++ b/src/java.base/share/classes/sun/security/provider/SHA.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2021, 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
@@ -62,7 +62,6 @@ public final class SHA extends DigestBase {
     public SHA() {
         super("SHA-1", 20, 64);
         state = new int[5];
-        W = new int[80];
         resetHashes();
     }
 
@@ -72,7 +71,7 @@ public final class SHA extends DigestBase {
     public Object clone() throws CloneNotSupportedException {
         SHA copy = (SHA) super.clone();
         copy.state = copy.state.clone();
-        copy.W = new int[80];
+        copy.W = null;
         return copy;
     }
 
@@ -83,7 +82,9 @@ public final class SHA extends DigestBase {
         // Load magic initialization constants.
         resetHashes();
         // clear out old data
-        Arrays.fill(W, 0);
+        if (W != null) {
+            Arrays.fill(W, 0);
+        }
     }
 
     private void resetHashes() {
@@ -132,11 +133,12 @@ public final class SHA extends DigestBase {
     private void implCompressCheck(byte[] buf, int ofs) {
         Objects.requireNonNull(buf);
 
-        // The checks performed by the method 'b2iBig64'
-        // are sufficient for the case when the method
-        // 'implCompress0' is replaced with a compiler
-        // intrinsic.
-        b2iBig64(buf, ofs, W);
+        // Checks similar to those performed by the method 'b2iBig64'
+        // are sufficient for the case when the method 'implCompress0' is
+        // replaced with a compiler intrinsic.
+        if (ofs < 0 || (buf.length - ofs) < 64) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
     }
 
     // The method 'implCompress0 seems not to use its parameters.
@@ -146,6 +148,10 @@ public final class SHA extends DigestBase {
     // must be passed as parameter to the method.
     @IntrinsicCandidate
     private void implCompress0(byte[] buf, int ofs) {
+        if (W == null) {
+            W = new int[80];
+        }
+        b2iBig64(buf, ofs, W);
         // The first 16 ints have the byte stream, compute the rest of
         // the buffer
         for (int t = 16; t <= 79; t++) {
diff --git a/src/java.base/share/classes/sun/security/provider/SHA2.java b/src/java.base/share/classes/sun/security/provider/SHA2.java
index 6f34b9bed0d..6c006feb064 100644
--- a/src/java.base/share/classes/sun/security/provider/SHA2.java
+++ b/src/java.base/share/classes/sun/security/provider/SHA2.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2021, 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
@@ -83,7 +83,6 @@ abstract class SHA2 extends DigestBase {
         super(name, digestLength, 64);
         this.initialHashes = initialHashes;
         state = new int[8];
-        W = new int[64];
         resetHashes();
     }
 
@@ -92,7 +91,9 @@ abstract class SHA2 extends DigestBase {
      */
     void implReset() {
         resetHashes();
-        Arrays.fill(W, 0);
+        if (W != null) {
+            Arrays.fill(W, 0);
+        }
     }
 
     private void resetHashes() {
@@ -124,11 +125,12 @@ abstract class SHA2 extends DigestBase {
     private void implCompressCheck(byte[] buf, int ofs) {
         Objects.requireNonNull(buf);
 
-        // The checks performed by the method 'b2iBig64'
-        // are sufficient for the case when the method
-        // 'implCompressImpl' is replaced with a compiler
-        // intrinsic.
-        b2iBig64(buf, ofs, W);
+        // Checks similar to those performed by the method 'b2iBig64'
+        // are sufficient for the case when the method 'implCompress0' is
+        // replaced with a compiler intrinsic.
+        if (ofs < 0 || (buf.length - ofs) < 64) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
     }
 
     // The method 'implCompressImpl' seems not to use its parameters.
@@ -138,6 +140,10 @@ abstract class SHA2 extends DigestBase {
     // must be passed as parameter to the method.
     @IntrinsicCandidate
     private void implCompress0(byte[] buf, int ofs) {
+        if (W == null) {
+            W = new int[64];
+        }
+        b2iBig64(buf, ofs, W);
         // The first 16 ints are from the byte stream, compute the rest of
         // the W[]'s
         for (int t = 16; t < ITERATION; t++) {
@@ -220,7 +226,7 @@ abstract class SHA2 extends DigestBase {
     public Object clone() throws CloneNotSupportedException {
         SHA2 copy = (SHA2) super.clone();
         copy.state = copy.state.clone();
-        copy.W = new int[64];
+        copy.W = null;
         return copy;
     }
 
diff --git a/src/java.base/share/classes/sun/security/provider/SHA5.java b/src/java.base/share/classes/sun/security/provider/SHA5.java
index b2cb790df5a..5ab91c644c6 100644
--- a/src/java.base/share/classes/sun/security/provider/SHA5.java
+++ b/src/java.base/share/classes/sun/security/provider/SHA5.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2021, 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
@@ -98,13 +98,14 @@ abstract class SHA5 extends DigestBase {
         super(name, digestLength, 128);
         this.initialHashes = initialHashes;
         state = new long[8];
-        W = new long[80];
         resetHashes();
     }
 
     final void implReset() {
         resetHashes();
-        Arrays.fill(W, 0L);
+        if (W != null) {
+            Arrays.fill(W, 0L);
+        }
     }
 
     private void resetHashes() {
@@ -225,11 +226,12 @@ abstract class SHA5 extends DigestBase {
     private void implCompressCheck(byte[] buf, int ofs) {
         Objects.requireNonNull(buf);
 
-        // The checks performed by the method 'b2iBig128'
-        // are sufficient for the case when the method
-        // 'implCompressImpl' is replaced with a compiler
-        // intrinsic.
-        b2lBig128(buf, ofs, W);
+        // Checks similar to those performed by the method 'b2lBig128'
+        // are sufficient for the case when the method 'implCompress0' is
+        // replaced with a compiler intrinsic.
+        if (ofs < 0 || (buf.length - ofs) < 128) {
+            throw new ArrayIndexOutOfBoundsException();
+        }
     }
 
     // The method 'implCompressImpl' seems not to use its parameters.
@@ -239,6 +241,10 @@ abstract class SHA5 extends DigestBase {
     // must be passed as parameter to the method.
     @IntrinsicCandidate
     private final void implCompress0(byte[] buf, int ofs) {
+        if (W == null) {
+            W = new long[80];
+        }
+        b2lBig128(buf, ofs, W);
         // The first 16 longs are from the byte stream, compute the rest of
         // the W[]'s
         for (int t = 16; t < ITERATION; t++) {
@@ -280,7 +286,7 @@ abstract class SHA5 extends DigestBase {
     public Object clone() throws CloneNotSupportedException {
         SHA5 copy = (SHA5) super.clone();
         copy.state = copy.state.clone();
-        copy.W = new long[80];
+        copy.W = null;
         return copy;
     }
 
diff --git a/test/micro/org/openjdk/bench/java/security/MessageDigests.java b/test/micro/org/openjdk/bench/java/security/MessageDigests.java
index 6b25f6dae35..2969baaa22e 100644
--- a/test/micro/org/openjdk/bench/java/security/MessageDigests.java
+++ b/test/micro/org/openjdk/bench/java/security/MessageDigests.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2021, 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
@@ -45,8 +45,8 @@ import org.openjdk.jmh.annotations.Warmup;
  */
 @State(Scope.Thread)
 @OutputTimeUnit(TimeUnit.MILLISECONDS)
-@Warmup(iterations = 5)
-@Measurement(iterations = 10)
+@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
 @Fork(jvmArgsAppend = {"-Xms1024m", "-Xmx1024m", "-Xmn768m", "-XX:+UseParallelGC"}, value = 5)
 public class MessageDigests {
 
@@ -77,4 +77,15 @@ public class MessageDigests {
     public byte[] digest() throws DigestException {
         return digester.digest(inputBytes);
     }
+
+    @Benchmark
+    public byte[] getAndDigest() throws DigestException, NoSuchAlgorithmException, NoSuchProviderException {
+        MessageDigest md;
+        if ("DEFAULT".equals(provider)) {
+            md = MessageDigest.getInstance(digesterName);
+        } else {
+            md = MessageDigest.getInstance(digesterName, provider);
+        }
+        return md.digest(inputBytes);
+    }
 }
diff --git a/test/micro/org/openjdk/bench/java/util/UUIDBench.java b/test/micro/org/openjdk/bench/java/util/UUIDBench.java
index 90c0a075286..76fef583f0b 100644
--- a/test/micro/org/openjdk/bench/java/util/UUIDBench.java
+++ b/test/micro/org/openjdk/bench/java/util/UUIDBench.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2021, 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
@@ -37,6 +37,8 @@ public class UUIDBench {
     @Param("20000")
     private int size;
 
+    private byte[][] uuidBytes;
+
     private UUID[] uuids;
 
     private String[] uuidStrings;
@@ -45,11 +47,14 @@ public class UUIDBench {
 
     @Setup
     public void setup() {
+        uuidBytes = new byte[size][];
         uuids = new UUID[size];
         uuidStrings = new String[size];
+        java.util.Random r = new java.util.Random(0);
         for (int i = 0; i < this.uuidStrings.length; i++) {
             final UUID uuid = UUID.randomUUID();
-
+            this.uuidBytes[i] = new byte[16];
+            r.nextBytes(this.uuidBytes[i]);
             this.uuids[i] = uuid;
             this.uuidStrings[i] = uuid.toString();
         }
@@ -72,4 +77,9 @@ public class UUIDBench {
     public String toString() {
         return uuids[index].toString();
     }
+
+    @Benchmark
+    public UUID fromType3Bytes() {
+        return UUID.nameUUIDFromBytes(uuidBytes[index]);
+    }
 }