Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/provider/ByteArrayAccess.java
38830 views
/*1* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider;2627import static java.lang.Integer.reverseBytes;28import static java.lang.Long.reverseBytes;2930import java.nio.ByteOrder;3132import sun.misc.Unsafe;3334/**35* Optimized methods for converting between byte[] and int[]/long[], both for36* big endian and little endian byte orders.37*38* Currently, it includes a default code path plus two optimized code paths.39* One is for little endian architectures that support full speed int/long40* access at unaligned addresses (i.e. x86/amd64). The second is for big endian41* architectures (that only support correctly aligned access), such as SPARC.42* These are the only platforms we currently support, but other optimized43* variants could be added as needed.44*45* NOTE that ArrayIndexOutOfBoundsException will be thrown if the bounds checks46* failed.47*48* This class may also be helpful in improving the performance of the49* crypto code in the SunJCE provider. However, for now it is only accessible by50* the message digest implementation in the SUN provider.51*52* @since 1.653* @author Andreas Sterbenz54*/55final class ByteArrayAccess {5657private ByteArrayAccess() {58// empty59}6061private static final Unsafe unsafe = Unsafe.getUnsafe();6263// whether to use the optimized path for little endian platforms that64// support full speed unaligned memory access.65private static final boolean littleEndianUnaligned;6667// whether to use the optimzied path for big endian platforms that68// support only correctly aligned full speed memory access.69// (Note that on SPARC unaligned memory access is possible, but it is70// implemented using a software trap and therefore very slow)71private static final boolean bigEndian;7273private final static int byteArrayOfs = unsafe.arrayBaseOffset(byte[].class);7475static {76boolean scaleOK = ((unsafe.arrayIndexScale(byte[].class) == 1)77&& (unsafe.arrayIndexScale(int[].class) == 4)78&& (unsafe.arrayIndexScale(long[].class) == 8)79&& ((byteArrayOfs & 3) == 0));8081ByteOrder byteOrder = ByteOrder.nativeOrder();82littleEndianUnaligned =83scaleOK && unaligned() && (byteOrder == ByteOrder.LITTLE_ENDIAN);84bigEndian =85scaleOK && (byteOrder == ByteOrder.BIG_ENDIAN);86}8788// Return whether this platform supports full speed int/long memory access89// at unaligned addresses.90// This code was copied from java.nio.Bits because there is no equivalent91// public API.92private static boolean unaligned() {93String arch = java.security.AccessController.doPrivileged94(new sun.security.action.GetPropertyAction("os.arch", ""));95return arch.equals("i386") || arch.equals("x86") || arch.equals("amd64")96|| arch.equals("x86_64") || arch.equals("ppc64") || arch.equals("ppc64le")97|| arch.equals("aarch64");98}99100/**101* byte[] to int[] conversion, little endian byte order.102*/103static void b2iLittle(byte[] in, int inOfs, int[] out, int outOfs, int len) {104if ((inOfs < 0) || ((in.length - inOfs) < len) ||105(outOfs < 0) || ((out.length - outOfs) < len/4)) {106throw new ArrayIndexOutOfBoundsException();107}108if (littleEndianUnaligned) {109inOfs += byteArrayOfs;110len += inOfs;111while (inOfs < len) {112out[outOfs++] = unsafe.getInt(in, (long)inOfs);113inOfs += 4;114}115} else if (bigEndian && ((inOfs & 3) == 0)) {116inOfs += byteArrayOfs;117len += inOfs;118while (inOfs < len) {119out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));120inOfs += 4;121}122} else {123len += inOfs;124while (inOfs < len) {125out[outOfs++] = ((in[inOfs ] & 0xff) )126| ((in[inOfs + 1] & 0xff) << 8)127| ((in[inOfs + 2] & 0xff) << 16)128| ((in[inOfs + 3] ) << 24);129inOfs += 4;130}131}132}133134// Special optimization of b2iLittle(in, inOfs, out, 0, 64)135static void b2iLittle64(byte[] in, int inOfs, int[] out) {136if ((inOfs < 0) || ((in.length - inOfs) < 64) ||137(out.length < 16)) {138throw new ArrayIndexOutOfBoundsException();139}140if (littleEndianUnaligned) {141inOfs += byteArrayOfs;142out[ 0] = unsafe.getInt(in, (long)(inOfs ));143out[ 1] = unsafe.getInt(in, (long)(inOfs + 4));144out[ 2] = unsafe.getInt(in, (long)(inOfs + 8));145out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));146out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));147out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));148out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));149out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));150out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));151out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));152out[10] = unsafe.getInt(in, (long)(inOfs + 40));153out[11] = unsafe.getInt(in, (long)(inOfs + 44));154out[12] = unsafe.getInt(in, (long)(inOfs + 48));155out[13] = unsafe.getInt(in, (long)(inOfs + 52));156out[14] = unsafe.getInt(in, (long)(inOfs + 56));157out[15] = unsafe.getInt(in, (long)(inOfs + 60));158} else if (bigEndian && ((inOfs & 3) == 0)) {159inOfs += byteArrayOfs;160out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs )));161out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 4)));162out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 8)));163out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));164out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));165out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));166out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));167out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));168out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));169out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));170out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));171out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));172out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));173out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));174out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));175out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));176} else {177b2iLittle(in, inOfs, out, 0, 64);178}179}180181/**182* int[] to byte[] conversion, little endian byte order.183*/184static void i2bLittle(int[] in, int inOfs, byte[] out, int outOfs, int len) {185if ((inOfs < 0) || ((in.length - inOfs) < len/4) ||186(outOfs < 0) || ((out.length - outOfs) < len)) {187throw new ArrayIndexOutOfBoundsException();188}189if (littleEndianUnaligned) {190outOfs += byteArrayOfs;191len += outOfs;192while (outOfs < len) {193unsafe.putInt(out, (long)outOfs, in[inOfs++]);194outOfs += 4;195}196} else if (bigEndian && ((outOfs & 3) == 0)) {197outOfs += byteArrayOfs;198len += outOfs;199while (outOfs < len) {200unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));201outOfs += 4;202}203} else {204len += outOfs;205while (outOfs < len) {206int i = in[inOfs++];207out[outOfs++] = (byte)(i );208out[outOfs++] = (byte)(i >> 8);209out[outOfs++] = (byte)(i >> 16);210out[outOfs++] = (byte)(i >> 24);211}212}213}214215// Store one 32-bit value into out[outOfs..outOfs+3] in little endian order.216static void i2bLittle4(int val, byte[] out, int outOfs) {217if ((outOfs < 0) || ((out.length - outOfs) < 4)) {218throw new ArrayIndexOutOfBoundsException();219}220if (littleEndianUnaligned) {221unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);222} else if (bigEndian && ((outOfs & 3) == 0)) {223unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));224} else {225out[outOfs ] = (byte)(val );226out[outOfs + 1] = (byte)(val >> 8);227out[outOfs + 2] = (byte)(val >> 16);228out[outOfs + 3] = (byte)(val >> 24);229}230}231232/**233* byte[] to int[] conversion, big endian byte order.234*/235static void b2iBig(byte[] in, int inOfs, int[] out, int outOfs, int len) {236if ((inOfs < 0) || ((in.length - inOfs) < len) ||237(outOfs < 0) || ((out.length - outOfs) < len/4)) {238throw new ArrayIndexOutOfBoundsException();239}240if (littleEndianUnaligned) {241inOfs += byteArrayOfs;242len += inOfs;243while (inOfs < len) {244out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));245inOfs += 4;246}247} else if (bigEndian && ((inOfs & 3) == 0)) {248inOfs += byteArrayOfs;249len += inOfs;250while (inOfs < len) {251out[outOfs++] = unsafe.getInt(in, (long)inOfs);252inOfs += 4;253}254} else {255len += inOfs;256while (inOfs < len) {257out[outOfs++] = ((in[inOfs + 3] & 0xff) )258| ((in[inOfs + 2] & 0xff) << 8)259| ((in[inOfs + 1] & 0xff) << 16)260| ((in[inOfs ] ) << 24);261inOfs += 4;262}263}264}265266// Special optimization of b2iBig(in, inOfs, out, 0, 64)267static void b2iBig64(byte[] in, int inOfs, int[] out) {268if ((inOfs < 0) || ((in.length - inOfs) < 64) ||269(out.length < 16)) {270throw new ArrayIndexOutOfBoundsException();271}272if (littleEndianUnaligned) {273inOfs += byteArrayOfs;274out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs )));275out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 4)));276out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 8)));277out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));278out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));279out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));280out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));281out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));282out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));283out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));284out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));285out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));286out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));287out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));288out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));289out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));290} else if (bigEndian && ((inOfs & 3) == 0)) {291inOfs += byteArrayOfs;292out[ 0] = unsafe.getInt(in, (long)(inOfs ));293out[ 1] = unsafe.getInt(in, (long)(inOfs + 4));294out[ 2] = unsafe.getInt(in, (long)(inOfs + 8));295out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));296out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));297out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));298out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));299out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));300out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));301out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));302out[10] = unsafe.getInt(in, (long)(inOfs + 40));303out[11] = unsafe.getInt(in, (long)(inOfs + 44));304out[12] = unsafe.getInt(in, (long)(inOfs + 48));305out[13] = unsafe.getInt(in, (long)(inOfs + 52));306out[14] = unsafe.getInt(in, (long)(inOfs + 56));307out[15] = unsafe.getInt(in, (long)(inOfs + 60));308} else {309b2iBig(in, inOfs, out, 0, 64);310}311}312313/**314* int[] to byte[] conversion, big endian byte order.315*/316static void i2bBig(int[] in, int inOfs, byte[] out, int outOfs, int len) {317if ((inOfs < 0) || ((in.length - inOfs) < len/4) ||318(outOfs < 0) || ((out.length - outOfs) < len)) {319throw new ArrayIndexOutOfBoundsException();320}321if (littleEndianUnaligned) {322outOfs += byteArrayOfs;323len += outOfs;324while (outOfs < len) {325unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));326outOfs += 4;327}328} else if (bigEndian && ((outOfs & 3) == 0)) {329outOfs += byteArrayOfs;330len += outOfs;331while (outOfs < len) {332unsafe.putInt(out, (long)outOfs, in[inOfs++]);333outOfs += 4;334}335} else {336len += outOfs;337while (outOfs < len) {338int i = in[inOfs++];339out[outOfs++] = (byte)(i >> 24);340out[outOfs++] = (byte)(i >> 16);341out[outOfs++] = (byte)(i >> 8);342out[outOfs++] = (byte)(i );343}344}345}346347// Store one 32-bit value into out[outOfs..outOfs+3] in big endian order.348static void i2bBig4(int val, byte[] out, int outOfs) {349if ((outOfs < 0) || ((out.length - outOfs) < 4)) {350throw new ArrayIndexOutOfBoundsException();351}352if (littleEndianUnaligned) {353unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));354} else if (bigEndian && ((outOfs & 3) == 0)) {355unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);356} else {357out[outOfs ] = (byte)(val >> 24);358out[outOfs + 1] = (byte)(val >> 16);359out[outOfs + 2] = (byte)(val >> 8);360out[outOfs + 3] = (byte)(val );361}362}363364/**365* byte[] to long[] conversion, big endian byte order.366*/367static void b2lBig(byte[] in, int inOfs, long[] out, int outOfs, int len) {368if ((inOfs < 0) || ((in.length - inOfs) < len) ||369(outOfs < 0) || ((out.length - outOfs) < len/8)) {370throw new ArrayIndexOutOfBoundsException();371}372if (littleEndianUnaligned) {373inOfs += byteArrayOfs;374len += inOfs;375while (inOfs < len) {376out[outOfs++] = reverseBytes(unsafe.getLong(in, (long)inOfs));377inOfs += 8;378}379} else if (bigEndian && ((inOfs & 3) == 0)) {380// In the current HotSpot memory layout, the first element of a381// byte[] is only 32-bit aligned, not 64-bit.382// That means we could use getLong() only for offset 4, 12, etc.,383// which would rarely occur in practice. Instead, we use an384// optimization that uses getInt() so that it works for offset 0.385inOfs += byteArrayOfs;386len += inOfs;387while (inOfs < len) {388out[outOfs++] =389((long)unsafe.getInt(in, (long)inOfs) << 32)390| (unsafe.getInt(in, (long)(inOfs + 4)) & 0xffffffffL);391inOfs += 8;392}393} else {394len += inOfs;395while (inOfs < len) {396int i1 = ((in[inOfs + 3] & 0xff) )397| ((in[inOfs + 2] & 0xff) << 8)398| ((in[inOfs + 1] & 0xff) << 16)399| ((in[inOfs ] ) << 24);400inOfs += 4;401int i2 = ((in[inOfs + 3] & 0xff) )402| ((in[inOfs + 2] & 0xff) << 8)403| ((in[inOfs + 1] & 0xff) << 16)404| ((in[inOfs ] ) << 24);405out[outOfs++] = ((long)i1 << 32) | (i2 & 0xffffffffL);406inOfs += 4;407}408}409}410411// Special optimization of b2lBig(in, inOfs, out, 0, 128)412static void b2lBig128(byte[] in, int inOfs, long[] out) {413if ((inOfs < 0) || ((in.length - inOfs) < 128) ||414(out.length < 16)) {415throw new ArrayIndexOutOfBoundsException();416}417if (littleEndianUnaligned) {418inOfs += byteArrayOfs;419out[ 0] = reverseBytes(unsafe.getLong(in, (long)(inOfs )));420out[ 1] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 8)));421out[ 2] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 16)));422out[ 3] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 24)));423out[ 4] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 32)));424out[ 5] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 40)));425out[ 6] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 48)));426out[ 7] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 56)));427out[ 8] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 64)));428out[ 9] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 72)));429out[10] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 80)));430out[11] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 88)));431out[12] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 96)));432out[13] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 104)));433out[14] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 112)));434out[15] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 120)));435} else {436// no optimization for big endian, see comments in b2lBig437b2lBig(in, inOfs, out, 0, 128);438}439}440441/**442* long[] to byte[] conversion, big endian byte order.443*/444static void l2bBig(long[] in, int inOfs, byte[] out, int outOfs, int len) {445if ((inOfs < 0) || ((in.length - inOfs) < len/8) ||446(outOfs < 0) || ((out.length - outOfs) < len)) {447throw new ArrayIndexOutOfBoundsException();448}449len += outOfs;450while (outOfs < len) {451long i = in[inOfs++];452out[outOfs++] = (byte)(i >> 56);453out[outOfs++] = (byte)(i >> 48);454out[outOfs++] = (byte)(i >> 40);455out[outOfs++] = (byte)(i >> 32);456out[outOfs++] = (byte)(i >> 24);457out[outOfs++] = (byte)(i >> 16);458out[outOfs++] = (byte)(i >> 8);459out[outOfs++] = (byte)(i );460}461}462}463464465