diff --git a/src/java.base/share/classes/java/util/Base64.java b/src/java.base/share/classes/java/util/Base64.java --- a/src/java.base/share/classes/java/util/Base64.java +++ b/src/java.base/share/classes/java/util/Base64.java @@ -742,9 +742,32 @@ return 3 * (int) ((len + 3L) / 4) - paddings; } - private int decode0(byte[] src, int sp, int sl, byte[] dst) { + // decodeBlock() can be overridden by an arch-specific intrinsic. + // decodeBlock is allowed to not decode all the (legal) bytes that + // are passed to it. It can choose to decode all, none, or a + // variable-sized prefix of the data. This allows the intrinsic to + // decode in chunks of the source that of a favorable size for the + // specific processor it's running on. For example, some + // processors may do better at decoding 256 byte blocks at a time, + // and another type may choose 32 bytes at a time, leaving the (sl + // % block_size) bytes for decodeBlockSlow to finish up. + // + // If any illegal characters are encountered in the intrinsic, it + // will simply return a -1, in which case decodeBlockSlow will be + // called to pinpoint the exact cause of the problem. + // + // If the intrinsic function does not process all of the bytes, + // it should process a multiple of four of the input characters, + // making the returned destination length a multiple of three. + // + @HotSpotIntrinsicCandidate + private int decodeBlock(byte[] src, int sp, int sl, byte[] dst, boolean isURL, boolean isMIME) { + // The non-intrinsic function simply forces calling decodeBlockSlow + return -1; + } + + private int decodeBlockSlow(byte[] src, int sp, int sl, byte[] dst, int dp) { int[] base64 = isURL ? fromBase64URL : fromBase64; - int dp = 0; int bits = 0; int shiftto = 18; // pos of first byte of 4-byte atom @@ -821,6 +844,43 @@ } return dp; } + + private int decode0(byte[] src, int sp, int sl, byte[] dst) { + int dl = decodeBlock(src, sp, sl, dst, isURL, isMIME); + if (dl == -1) { + // Run decodeBlockSlow to pinpoint the location of the + // error. + return decodeBlockSlow(src, sp, sl, dst, 0); + } else { + // Calculate how many characters were processed by how + // many bytes of data were returned. + int chars_decoded = ((dl + 2) / 3) * 4; + if (sl > chars_decoded) { + // Base64 characters always come in groups of four, + // producing three bytes of binary data (except for + // on the final four-character piece where it can + // produce one to three data bytes depending on how + // many fill characters there - zero, one, or + // two). The only case where there should be a + // non-multiple of three returned is if the + // intrinsic has processed all of the characters + // passed to it. At this point in the logic, + // however, we know the instrinsic hasn't processed + // all of the chracters. + // + // Round dl down to the nearest three-byte boundary + dl = (dl / 3) * 3; + + // Recalculate chars_decoded based on the rounded dl + chars_decoded = (dl / 3) * 4; + + // Finish the process using decodeBlockSlow + return decodeBlockSlow(src, sp + chars_decoded, sl, dst, dl); + } else { + return dl; + } + } + } } /*