001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.security.provider;
027:
028: import static java.lang.Integer.reverseBytes;
029: import static java.lang.Long.reverseBytes;
030:
031: import java.nio.ByteOrder;
032:
033: import sun.misc.Unsafe;
034:
035: /**
036: * Optimized methods for converting between byte[] and int[]/long[], both for
037: * big endian and little endian byte orders.
038: *
039: * Currently, it includes a default code path plus two optimized code paths.
040: * One is for little endian architectures that support full speed int/long
041: * access at unaligned addresses (i.e. x86/amd64). The second is for big endian
042: * architectures (that only support correctly aligned access), such as SPARC.
043: * These are the only platforms we currently support, but other optimized
044: * variants could be added as needed.
045: *
046: * NOTE that because this code performs unchecked direct memory access, it
047: * MUST be restricted to trusted code. It is imperative that the caller protects
048: * against out of bounds memory access by performing the necessary bounds
049: * checks before calling methods in this class.
050: *
051: * This class may also be helpful in improving the performance of the
052: * crypto code in the SunJCE provider. However, for now it is only accessible by
053: * the message digest implementation in the SUN provider.
054: *
055: * @since 1.6
056: * @version 1.7, 05/05/07
057: * @author Andreas Sterbenz
058: */
059: final class ByteArrayAccess {
060:
061: private ByteArrayAccess() {
062: // empty
063: }
064:
065: private static final Unsafe unsafe = Unsafe.getUnsafe();
066:
067: // whether to use the optimized path for little endian platforms that
068: // support full speed unaligned memory access.
069: private static final boolean littleEndianUnaligned;
070:
071: // whether to use the optimzied path for big endian platforms that
072: // support only correctly aligned full speed memory access.
073: // (Note that on SPARC unaligned memory access is possible, but it is
074: // implemented using a software trap and therefore very slow)
075: private static final boolean bigEndian;
076:
077: private final static int byteArrayOfs = unsafe
078: .arrayBaseOffset(byte[].class);
079:
080: static {
081: boolean scaleOK = ((unsafe.arrayIndexScale(byte[].class) == 1)
082: && (unsafe.arrayIndexScale(int[].class) == 4)
083: && (unsafe.arrayIndexScale(long[].class) == 8) && ((byteArrayOfs & 3) == 0));
084:
085: ByteOrder byteOrder = ByteOrder.nativeOrder();
086: littleEndianUnaligned = scaleOK && unaligned()
087: && (byteOrder == ByteOrder.LITTLE_ENDIAN);
088: bigEndian = scaleOK && (byteOrder == ByteOrder.BIG_ENDIAN);
089: }
090:
091: // Return whether this platform supports full speed int/long memory access
092: // at unaligned addresses.
093: // This code was copied from java.nio.Bits because there is no equivalent
094: // public API.
095: private static boolean unaligned() {
096: String arch = java.security.AccessController
097: .doPrivileged(new sun.security.action.GetPropertyAction(
098: "os.arch", ""));
099: return arch.equals("i386") || arch.equals("x86")
100: || arch.equals("amd64");
101: }
102:
103: /**
104: * byte[] to int[] conversion, little endian byte order.
105: */
106: static void b2iLittle(byte[] in, int inOfs, int[] out, int outOfs,
107: int len) {
108: if (littleEndianUnaligned) {
109: inOfs += byteArrayOfs;
110: len += inOfs;
111: while (inOfs < len) {
112: out[outOfs++] = unsafe.getInt(in, (long) inOfs);
113: inOfs += 4;
114: }
115: } else if (bigEndian && ((inOfs & 3) == 0)) {
116: inOfs += byteArrayOfs;
117: len += inOfs;
118: while (inOfs < len) {
119: out[outOfs++] = reverseBytes(unsafe.getInt(in,
120: (long) inOfs));
121: inOfs += 4;
122: }
123: } else {
124: len += inOfs;
125: while (inOfs < len) {
126: out[outOfs++] = ((in[inOfs] & 0xff))
127: | ((in[inOfs + 1] & 0xff) << 8)
128: | ((in[inOfs + 2] & 0xff) << 16)
129: | ((in[inOfs + 3]) << 24);
130: inOfs += 4;
131: }
132: }
133: }
134:
135: // Special optimization of b2iLittle(in, inOfs, out, 0, 64)
136: static void b2iLittle64(byte[] in, int inOfs, int[] out) {
137: if (littleEndianUnaligned) {
138: inOfs += byteArrayOfs;
139: out[0] = unsafe.getInt(in, (long) (inOfs));
140: out[1] = unsafe.getInt(in, (long) (inOfs + 4));
141: out[2] = unsafe.getInt(in, (long) (inOfs + 8));
142: out[3] = unsafe.getInt(in, (long) (inOfs + 12));
143: out[4] = unsafe.getInt(in, (long) (inOfs + 16));
144: out[5] = unsafe.getInt(in, (long) (inOfs + 20));
145: out[6] = unsafe.getInt(in, (long) (inOfs + 24));
146: out[7] = unsafe.getInt(in, (long) (inOfs + 28));
147: out[8] = unsafe.getInt(in, (long) (inOfs + 32));
148: out[9] = unsafe.getInt(in, (long) (inOfs + 36));
149: out[10] = unsafe.getInt(in, (long) (inOfs + 40));
150: out[11] = unsafe.getInt(in, (long) (inOfs + 44));
151: out[12] = unsafe.getInt(in, (long) (inOfs + 48));
152: out[13] = unsafe.getInt(in, (long) (inOfs + 52));
153: out[14] = unsafe.getInt(in, (long) (inOfs + 56));
154: out[15] = unsafe.getInt(in, (long) (inOfs + 60));
155: } else if (bigEndian && ((inOfs & 3) == 0)) {
156: inOfs += byteArrayOfs;
157: out[0] = reverseBytes(unsafe.getInt(in, (long) (inOfs)));
158: out[1] = reverseBytes(unsafe.getInt(in, (long) (inOfs + 4)));
159: out[2] = reverseBytes(unsafe.getInt(in, (long) (inOfs + 8)));
160: out[3] = reverseBytes(unsafe
161: .getInt(in, (long) (inOfs + 12)));
162: out[4] = reverseBytes(unsafe
163: .getInt(in, (long) (inOfs + 16)));
164: out[5] = reverseBytes(unsafe
165: .getInt(in, (long) (inOfs + 20)));
166: out[6] = reverseBytes(unsafe
167: .getInt(in, (long) (inOfs + 24)));
168: out[7] = reverseBytes(unsafe
169: .getInt(in, (long) (inOfs + 28)));
170: out[8] = reverseBytes(unsafe
171: .getInt(in, (long) (inOfs + 32)));
172: out[9] = reverseBytes(unsafe
173: .getInt(in, (long) (inOfs + 36)));
174: out[10] = reverseBytes(unsafe.getInt(in,
175: (long) (inOfs + 40)));
176: out[11] = reverseBytes(unsafe.getInt(in,
177: (long) (inOfs + 44)));
178: out[12] = reverseBytes(unsafe.getInt(in,
179: (long) (inOfs + 48)));
180: out[13] = reverseBytes(unsafe.getInt(in,
181: (long) (inOfs + 52)));
182: out[14] = reverseBytes(unsafe.getInt(in,
183: (long) (inOfs + 56)));
184: out[15] = reverseBytes(unsafe.getInt(in,
185: (long) (inOfs + 60)));
186: } else {
187: b2iLittle(in, inOfs, out, 0, 64);
188: }
189: }
190:
191: /**
192: * int[] to byte[] conversion, little endian byte order.
193: */
194: static void i2bLittle(int[] in, int inOfs, byte[] out, int outOfs,
195: int len) {
196: if (littleEndianUnaligned) {
197: outOfs += byteArrayOfs;
198: len += outOfs;
199: while (outOfs < len) {
200: unsafe.putInt(out, (long) outOfs, in[inOfs++]);
201: outOfs += 4;
202: }
203: } else if (bigEndian && ((outOfs & 3) == 0)) {
204: outOfs += byteArrayOfs;
205: len += outOfs;
206: while (outOfs < len) {
207: unsafe.putInt(out, (long) outOfs,
208: reverseBytes(in[inOfs++]));
209: outOfs += 4;
210: }
211: } else {
212: len += outOfs;
213: while (outOfs < len) {
214: int i = in[inOfs++];
215: out[outOfs++] = (byte) (i);
216: out[outOfs++] = (byte) (i >> 8);
217: out[outOfs++] = (byte) (i >> 16);
218: out[outOfs++] = (byte) (i >> 24);
219: }
220: }
221: }
222:
223: // Store one 32-bit value into out[outOfs..outOfs+3] in little endian order.
224: static void i2bLittle4(int val, byte[] out, int outOfs) {
225: if (littleEndianUnaligned) {
226: unsafe.putInt(out, (long) (byteArrayOfs + outOfs), val);
227: } else if (bigEndian && ((outOfs & 3) == 0)) {
228: unsafe.putInt(out, (long) (byteArrayOfs + outOfs),
229: reverseBytes(val));
230: } else {
231: out[outOfs] = (byte) (val);
232: out[outOfs + 1] = (byte) (val >> 8);
233: out[outOfs + 2] = (byte) (val >> 16);
234: out[outOfs + 3] = (byte) (val >> 24);
235: }
236: }
237:
238: /**
239: * byte[] to int[] conversion, big endian byte order.
240: */
241: static void b2iBig(byte[] in, int inOfs, int[] out, int outOfs,
242: int len) {
243: if (littleEndianUnaligned) {
244: inOfs += byteArrayOfs;
245: len += inOfs;
246: while (inOfs < len) {
247: out[outOfs++] = reverseBytes(unsafe.getInt(in,
248: (long) inOfs));
249: inOfs += 4;
250: }
251: } else if (bigEndian && ((inOfs & 3) == 0)) {
252: inOfs += byteArrayOfs;
253: len += inOfs;
254: while (inOfs < len) {
255: out[outOfs++] = unsafe.getInt(in, (long) inOfs);
256: inOfs += 4;
257: }
258: } else {
259: len += inOfs;
260: while (inOfs < len) {
261: out[outOfs++] = ((in[inOfs + 3] & 0xff))
262: | ((in[inOfs + 2] & 0xff) << 8)
263: | ((in[inOfs + 1] & 0xff) << 16)
264: | ((in[inOfs]) << 24);
265: inOfs += 4;
266: }
267: }
268: }
269:
270: // Special optimization of b2iBig(in, inOfs, out, 0, 64)
271: static void b2iBig64(byte[] in, int inOfs, int[] out) {
272: if (littleEndianUnaligned) {
273: inOfs += byteArrayOfs;
274: out[0] = reverseBytes(unsafe.getInt(in, (long) (inOfs)));
275: out[1] = reverseBytes(unsafe.getInt(in, (long) (inOfs + 4)));
276: out[2] = reverseBytes(unsafe.getInt(in, (long) (inOfs + 8)));
277: out[3] = reverseBytes(unsafe
278: .getInt(in, (long) (inOfs + 12)));
279: out[4] = reverseBytes(unsafe
280: .getInt(in, (long) (inOfs + 16)));
281: out[5] = reverseBytes(unsafe
282: .getInt(in, (long) (inOfs + 20)));
283: out[6] = reverseBytes(unsafe
284: .getInt(in, (long) (inOfs + 24)));
285: out[7] = reverseBytes(unsafe
286: .getInt(in, (long) (inOfs + 28)));
287: out[8] = reverseBytes(unsafe
288: .getInt(in, (long) (inOfs + 32)));
289: out[9] = reverseBytes(unsafe
290: .getInt(in, (long) (inOfs + 36)));
291: out[10] = reverseBytes(unsafe.getInt(in,
292: (long) (inOfs + 40)));
293: out[11] = reverseBytes(unsafe.getInt(in,
294: (long) (inOfs + 44)));
295: out[12] = reverseBytes(unsafe.getInt(in,
296: (long) (inOfs + 48)));
297: out[13] = reverseBytes(unsafe.getInt(in,
298: (long) (inOfs + 52)));
299: out[14] = reverseBytes(unsafe.getInt(in,
300: (long) (inOfs + 56)));
301: out[15] = reverseBytes(unsafe.getInt(in,
302: (long) (inOfs + 60)));
303: } else if (bigEndian && ((inOfs & 3) == 0)) {
304: inOfs += byteArrayOfs;
305: out[0] = unsafe.getInt(in, (long) (inOfs));
306: out[1] = unsafe.getInt(in, (long) (inOfs + 4));
307: out[2] = unsafe.getInt(in, (long) (inOfs + 8));
308: out[3] = unsafe.getInt(in, (long) (inOfs + 12));
309: out[4] = unsafe.getInt(in, (long) (inOfs + 16));
310: out[5] = unsafe.getInt(in, (long) (inOfs + 20));
311: out[6] = unsafe.getInt(in, (long) (inOfs + 24));
312: out[7] = unsafe.getInt(in, (long) (inOfs + 28));
313: out[8] = unsafe.getInt(in, (long) (inOfs + 32));
314: out[9] = unsafe.getInt(in, (long) (inOfs + 36));
315: out[10] = unsafe.getInt(in, (long) (inOfs + 40));
316: out[11] = unsafe.getInt(in, (long) (inOfs + 44));
317: out[12] = unsafe.getInt(in, (long) (inOfs + 48));
318: out[13] = unsafe.getInt(in, (long) (inOfs + 52));
319: out[14] = unsafe.getInt(in, (long) (inOfs + 56));
320: out[15] = unsafe.getInt(in, (long) (inOfs + 60));
321: } else {
322: b2iBig(in, inOfs, out, 0, 64);
323: }
324: }
325:
326: /**
327: * int[] to byte[] conversion, big endian byte order.
328: */
329: static void i2bBig(int[] in, int inOfs, byte[] out, int outOfs,
330: int len) {
331: if (littleEndianUnaligned) {
332: outOfs += byteArrayOfs;
333: len += outOfs;
334: while (outOfs < len) {
335: unsafe.putInt(out, (long) outOfs,
336: reverseBytes(in[inOfs++]));
337: outOfs += 4;
338: }
339: } else if (bigEndian && ((outOfs & 3) == 0)) {
340: outOfs += byteArrayOfs;
341: len += outOfs;
342: while (outOfs < len) {
343: unsafe.putInt(out, (long) outOfs, in[inOfs++]);
344: outOfs += 4;
345: }
346: } else {
347: len += outOfs;
348: while (outOfs < len) {
349: int i = in[inOfs++];
350: out[outOfs++] = (byte) (i >> 24);
351: out[outOfs++] = (byte) (i >> 16);
352: out[outOfs++] = (byte) (i >> 8);
353: out[outOfs++] = (byte) (i);
354: }
355: }
356: }
357:
358: // Store one 32-bit value into out[outOfs..outOfs+3] in big endian order.
359: static void i2bBig4(int val, byte[] out, int outOfs) {
360: if (littleEndianUnaligned) {
361: unsafe.putInt(out, (long) (byteArrayOfs + outOfs),
362: reverseBytes(val));
363: } else if (bigEndian && ((outOfs & 3) == 0)) {
364: unsafe.putInt(out, (long) (byteArrayOfs + outOfs), val);
365: } else {
366: out[outOfs] = (byte) (val >> 24);
367: out[outOfs + 1] = (byte) (val >> 16);
368: out[outOfs + 2] = (byte) (val >> 8);
369: out[outOfs + 3] = (byte) (val);
370: }
371: }
372:
373: /**
374: * byte[] to long[] conversion, big endian byte order.
375: */
376: static void b2lBig(byte[] in, int inOfs, long[] out, int outOfs,
377: int len) {
378: if (littleEndianUnaligned) {
379: inOfs += byteArrayOfs;
380: len += inOfs;
381: while (inOfs < len) {
382: out[outOfs++] = reverseBytes(unsafe.getLong(in,
383: (long) inOfs));
384: inOfs += 8;
385: }
386: } else if (bigEndian && ((inOfs & 3) == 0)) {
387: // In the current HotSpot memory layout, the first element of a
388: // byte[] is only 32-bit aligned, not 64-bit.
389: // That means we could use getLong() only for offset 4, 12, etc.,
390: // which would rarely occur in practice. Instead, we use an
391: // optimization that uses getInt() so that it works for offset 0.
392: inOfs += byteArrayOfs;
393: len += inOfs;
394: while (inOfs < len) {
395: out[outOfs++] = ((long) unsafe.getInt(in, (long) inOfs) << 32)
396: | (unsafe.getInt(in, (long) (inOfs + 4)) & 0xffffffffL);
397: inOfs += 8;
398: }
399: } else {
400: len += inOfs;
401: while (inOfs < len) {
402: int i1 = ((in[inOfs + 3] & 0xff))
403: | ((in[inOfs + 2] & 0xff) << 8)
404: | ((in[inOfs + 1] & 0xff) << 16)
405: | ((in[inOfs]) << 24);
406: inOfs += 4;
407: int i2 = ((in[inOfs + 3] & 0xff))
408: | ((in[inOfs + 2] & 0xff) << 8)
409: | ((in[inOfs + 1] & 0xff) << 16)
410: | ((in[inOfs]) << 24);
411: out[outOfs++] = ((long) i1 << 32) | (i2 & 0xffffffffL);
412: inOfs += 4;
413: }
414: }
415: }
416:
417: // Special optimization of b2lBig(in, inOfs, out, 0, 128)
418: static void b2lBig128(byte[] in, int inOfs, long[] out) {
419: if (littleEndianUnaligned) {
420: inOfs += byteArrayOfs;
421: out[0] = reverseBytes(unsafe.getLong(in, (long) (inOfs)));
422: out[1] = reverseBytes(unsafe
423: .getLong(in, (long) (inOfs + 8)));
424: out[2] = reverseBytes(unsafe.getLong(in,
425: (long) (inOfs + 16)));
426: out[3] = reverseBytes(unsafe.getLong(in,
427: (long) (inOfs + 24)));
428: out[4] = reverseBytes(unsafe.getLong(in,
429: (long) (inOfs + 32)));
430: out[5] = reverseBytes(unsafe.getLong(in,
431: (long) (inOfs + 40)));
432: out[6] = reverseBytes(unsafe.getLong(in,
433: (long) (inOfs + 48)));
434: out[7] = reverseBytes(unsafe.getLong(in,
435: (long) (inOfs + 56)));
436: out[8] = reverseBytes(unsafe.getLong(in,
437: (long) (inOfs + 64)));
438: out[9] = reverseBytes(unsafe.getLong(in,
439: (long) (inOfs + 72)));
440: out[10] = reverseBytes(unsafe.getLong(in,
441: (long) (inOfs + 80)));
442: out[11] = reverseBytes(unsafe.getLong(in,
443: (long) (inOfs + 88)));
444: out[12] = reverseBytes(unsafe.getLong(in,
445: (long) (inOfs + 96)));
446: out[13] = reverseBytes(unsafe.getLong(in,
447: (long) (inOfs + 104)));
448: out[14] = reverseBytes(unsafe.getLong(in,
449: (long) (inOfs + 112)));
450: out[15] = reverseBytes(unsafe.getLong(in,
451: (long) (inOfs + 120)));
452: } else {
453: // no optimization for big endian, see comments in b2lBig
454: b2lBig(in, inOfs, out, 0, 128);
455: }
456: }
457:
458: /**
459: * long[] to byte[] conversion, big endian byte order.
460: */
461: static void l2bBig(long[] in, int inOfs, byte[] out, int outOfs,
462: int len) {
463: len += outOfs;
464: while (outOfs < len) {
465: long i = in[inOfs++];
466: out[outOfs++] = (byte) (i >> 56);
467: out[outOfs++] = (byte) (i >> 48);
468: out[outOfs++] = (byte) (i >> 40);
469: out[outOfs++] = (byte) (i >> 32);
470: out[outOfs++] = (byte) (i >> 24);
471: out[outOfs++] = (byte) (i >> 16);
472: out[outOfs++] = (byte) (i >> 8);
473: out[outOfs++] = (byte) (i);
474: }
475: }
476:
477: }
|