1/*
2 * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.security.provider;
27
28import static java.lang.Integer.reverseBytes;
29import static java.lang.Long.reverseBytes;
30
31import java.nio.ByteOrder;
32
33import jdk.internal.misc.Unsafe;
34
35/**
36 * Optimized methods for converting between byte[] and int[]/long[], both for
37 * big endian and little endian byte orders.
38 *
39 * Currently, it includes a default code path plus two optimized code paths.
40 * One is for little endian architectures that support full speed int/long
41 * access at unaligned addresses (i.e. x86/amd64). The second is for big endian
42 * architectures (that only support correctly aligned access), such as SPARC.
43 * These are the only platforms we currently support, but other optimized
44 * variants could be added as needed.
45 *
46 * NOTE that ArrayIndexOutOfBoundsException will be thrown if the bounds checks
47 * failed.
48 *
49 * This class may also be helpful in improving the performance of the
50 * crypto code in the SunJCE provider. However, for now it is only accessible by
51 * the message digest implementation in the SUN provider.
52 *
53 * @since   1.6
54 * @author  Andreas Sterbenz
55 */
56final class ByteArrayAccess {
57
58    private ByteArrayAccess() {
59        // empty
60    }
61
62    private static final Unsafe unsafe = Unsafe.getUnsafe();
63
64    // whether to use the optimized path for little endian platforms that
65    // support full speed unaligned memory access.
66    private static final boolean littleEndianUnaligned;
67
68    // whether to use the optimzied path for big endian platforms that
69    // support only correctly aligned full speed memory access.
70    // (Note that on SPARC unaligned memory access is possible, but it is
71    // implemented using a software trap and therefore very slow)
72    private static final boolean bigEndian;
73
74    private static final int byteArrayOfs = unsafe.arrayBaseOffset(byte[].class);
75
76    static {
77        boolean scaleOK = ((unsafe.arrayIndexScale(byte[].class) == 1)
78            && (unsafe.arrayIndexScale(int[].class) == 4)
79            && (unsafe.arrayIndexScale(long[].class) == 8)
80            && ((byteArrayOfs & 3) == 0));
81
82        ByteOrder byteOrder = ByteOrder.nativeOrder();
83        littleEndianUnaligned =
84            scaleOK && unaligned() && (byteOrder == ByteOrder.LITTLE_ENDIAN);
85        bigEndian =
86            scaleOK && (byteOrder == ByteOrder.BIG_ENDIAN);
87    }
88
89    // Return whether this platform supports full speed int/long memory access
90    // at unaligned addresses.
91    private static boolean unaligned() {
92        return unsafe.unalignedAccess();
93    }
94
95    /**
96     * byte[] to int[] conversion, little endian byte order.
97     */
98    static void b2iLittle(byte[] in, int inOfs, int[] out, int outOfs, int len) {
99        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
100            (outOfs < 0) || ((out.length - outOfs) < len/4)) {
101            throw new ArrayIndexOutOfBoundsException();
102        }
103        if (littleEndianUnaligned) {
104            inOfs += byteArrayOfs;
105            len += inOfs;
106            while (inOfs < len) {
107                out[outOfs++] = unsafe.getInt(in, (long)inOfs);
108                inOfs += 4;
109            }
110        } else if (bigEndian && ((inOfs & 3) == 0)) {
111            inOfs += byteArrayOfs;
112            len += inOfs;
113            while (inOfs < len) {
114                out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));
115                inOfs += 4;
116            }
117        } else {
118            len += inOfs;
119            while (inOfs < len) {
120                out[outOfs++] = ((in[inOfs    ] & 0xff)      )
121                              | ((in[inOfs + 1] & 0xff) <<  8)
122                              | ((in[inOfs + 2] & 0xff) << 16)
123                              | ((in[inOfs + 3]       ) << 24);
124                inOfs += 4;
125            }
126        }
127    }
128
129    // Special optimization of b2iLittle(in, inOfs, out, 0, 64)
130    static void b2iLittle64(byte[] in, int inOfs, int[] out) {
131        if ((inOfs < 0) || ((in.length - inOfs) < 64) ||
132            (out.length < 16)) {
133            throw new ArrayIndexOutOfBoundsException();
134        }
135        if (littleEndianUnaligned) {
136            inOfs += byteArrayOfs;
137            out[ 0] = unsafe.getInt(in, (long)(inOfs     ));
138            out[ 1] = unsafe.getInt(in, (long)(inOfs +  4));
139            out[ 2] = unsafe.getInt(in, (long)(inOfs +  8));
140            out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));
141            out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));
142            out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));
143            out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));
144            out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));
145            out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));
146            out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));
147            out[10] = unsafe.getInt(in, (long)(inOfs + 40));
148            out[11] = unsafe.getInt(in, (long)(inOfs + 44));
149            out[12] = unsafe.getInt(in, (long)(inOfs + 48));
150            out[13] = unsafe.getInt(in, (long)(inOfs + 52));
151            out[14] = unsafe.getInt(in, (long)(inOfs + 56));
152            out[15] = unsafe.getInt(in, (long)(inOfs + 60));
153        } else if (bigEndian && ((inOfs & 3) == 0)) {
154            inOfs += byteArrayOfs;
155            out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs     )));
156            out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs +  4)));
157            out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs +  8)));
158            out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));
159            out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));
160            out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));
161            out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));
162            out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));
163            out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));
164            out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));
165            out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));
166            out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));
167            out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));
168            out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));
169            out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));
170            out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));
171        } else {
172            b2iLittle(in, inOfs, out, 0, 64);
173        }
174    }
175
176    /**
177     * int[] to byte[] conversion, little endian byte order.
178     */
179    static void i2bLittle(int[] in, int inOfs, byte[] out, int outOfs, int len) {
180        if ((inOfs < 0) || ((in.length - inOfs) < len/4) ||
181            (outOfs < 0) || ((out.length - outOfs) < len)) {
182            throw new ArrayIndexOutOfBoundsException();
183        }
184        if (littleEndianUnaligned) {
185            outOfs += byteArrayOfs;
186            len += outOfs;
187            while (outOfs < len) {
188                unsafe.putInt(out, (long)outOfs, in[inOfs++]);
189                outOfs += 4;
190            }
191        } else if (bigEndian && ((outOfs & 3) == 0)) {
192            outOfs += byteArrayOfs;
193            len += outOfs;
194            while (outOfs < len) {
195                unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));
196                outOfs += 4;
197            }
198        } else {
199            len += outOfs;
200            while (outOfs < len) {
201                int i = in[inOfs++];
202                out[outOfs++] = (byte)(i      );
203                out[outOfs++] = (byte)(i >>  8);
204                out[outOfs++] = (byte)(i >> 16);
205                out[outOfs++] = (byte)(i >> 24);
206            }
207        }
208    }
209
210    // Store one 32-bit value into out[outOfs..outOfs+3] in little endian order.
211    static void i2bLittle4(int val, byte[] out, int outOfs) {
212        if ((outOfs < 0) || ((out.length - outOfs) < 4)) {
213            throw new ArrayIndexOutOfBoundsException();
214        }
215        if (littleEndianUnaligned) {
216            unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);
217        } else if (bigEndian && ((outOfs & 3) == 0)) {
218            unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));
219        } else {
220            out[outOfs    ] = (byte)(val      );
221            out[outOfs + 1] = (byte)(val >>  8);
222            out[outOfs + 2] = (byte)(val >> 16);
223            out[outOfs + 3] = (byte)(val >> 24);
224        }
225    }
226
227    /**
228     * byte[] to int[] conversion, big endian byte order.
229     */
230    static void b2iBig(byte[] in, int inOfs, int[] out, int outOfs, int len) {
231        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
232            (outOfs < 0) || ((out.length - outOfs) < len/4)) {
233            throw new ArrayIndexOutOfBoundsException();
234        }
235        if (littleEndianUnaligned) {
236            inOfs += byteArrayOfs;
237            len += inOfs;
238            while (inOfs < len) {
239                out[outOfs++] = reverseBytes(unsafe.getInt(in, (long)inOfs));
240                inOfs += 4;
241            }
242        } else if (bigEndian && ((inOfs & 3) == 0)) {
243            inOfs += byteArrayOfs;
244            len += inOfs;
245            while (inOfs < len) {
246                out[outOfs++] = unsafe.getInt(in, (long)inOfs);
247                inOfs += 4;
248            }
249        } else {
250            len += inOfs;
251            while (inOfs < len) {
252                out[outOfs++] = ((in[inOfs + 3] & 0xff)      )
253                              | ((in[inOfs + 2] & 0xff) <<  8)
254                              | ((in[inOfs + 1] & 0xff) << 16)
255                              | ((in[inOfs    ]       ) << 24);
256                inOfs += 4;
257            }
258        }
259    }
260
261    // Special optimization of b2iBig(in, inOfs, out, 0, 64)
262    static void b2iBig64(byte[] in, int inOfs, int[] out) {
263        if ((inOfs < 0) || ((in.length - inOfs) < 64) ||
264            (out.length < 16)) {
265            throw new ArrayIndexOutOfBoundsException();
266        }
267        if (littleEndianUnaligned) {
268            inOfs += byteArrayOfs;
269            out[ 0] = reverseBytes(unsafe.getInt(in, (long)(inOfs     )));
270            out[ 1] = reverseBytes(unsafe.getInt(in, (long)(inOfs +  4)));
271            out[ 2] = reverseBytes(unsafe.getInt(in, (long)(inOfs +  8)));
272            out[ 3] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 12)));
273            out[ 4] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 16)));
274            out[ 5] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 20)));
275            out[ 6] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 24)));
276            out[ 7] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 28)));
277            out[ 8] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 32)));
278            out[ 9] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 36)));
279            out[10] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 40)));
280            out[11] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 44)));
281            out[12] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 48)));
282            out[13] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 52)));
283            out[14] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 56)));
284            out[15] = reverseBytes(unsafe.getInt(in, (long)(inOfs + 60)));
285        } else if (bigEndian && ((inOfs & 3) == 0)) {
286            inOfs += byteArrayOfs;
287            out[ 0] = unsafe.getInt(in, (long)(inOfs     ));
288            out[ 1] = unsafe.getInt(in, (long)(inOfs +  4));
289            out[ 2] = unsafe.getInt(in, (long)(inOfs +  8));
290            out[ 3] = unsafe.getInt(in, (long)(inOfs + 12));
291            out[ 4] = unsafe.getInt(in, (long)(inOfs + 16));
292            out[ 5] = unsafe.getInt(in, (long)(inOfs + 20));
293            out[ 6] = unsafe.getInt(in, (long)(inOfs + 24));
294            out[ 7] = unsafe.getInt(in, (long)(inOfs + 28));
295            out[ 8] = unsafe.getInt(in, (long)(inOfs + 32));
296            out[ 9] = unsafe.getInt(in, (long)(inOfs + 36));
297            out[10] = unsafe.getInt(in, (long)(inOfs + 40));
298            out[11] = unsafe.getInt(in, (long)(inOfs + 44));
299            out[12] = unsafe.getInt(in, (long)(inOfs + 48));
300            out[13] = unsafe.getInt(in, (long)(inOfs + 52));
301            out[14] = unsafe.getInt(in, (long)(inOfs + 56));
302            out[15] = unsafe.getInt(in, (long)(inOfs + 60));
303        } else {
304            b2iBig(in, inOfs, out, 0, 64);
305        }
306    }
307
308    /**
309     * int[] to byte[] conversion, big endian byte order.
310     */
311    static void i2bBig(int[] in, int inOfs, byte[] out, int outOfs, int len) {
312        if ((inOfs < 0) || ((in.length - inOfs) < len/4) ||
313            (outOfs < 0) || ((out.length - outOfs) < len)) {
314            throw new ArrayIndexOutOfBoundsException();
315        }
316        if (littleEndianUnaligned) {
317            outOfs += byteArrayOfs;
318            len += outOfs;
319            while (outOfs < len) {
320                unsafe.putInt(out, (long)outOfs, reverseBytes(in[inOfs++]));
321                outOfs += 4;
322            }
323        } else if (bigEndian && ((outOfs & 3) == 0)) {
324            outOfs += byteArrayOfs;
325            len += outOfs;
326            while (outOfs < len) {
327                unsafe.putInt(out, (long)outOfs, in[inOfs++]);
328                outOfs += 4;
329            }
330        } else {
331            len += outOfs;
332            while (outOfs < len) {
333                int i = in[inOfs++];
334                out[outOfs++] = (byte)(i >> 24);
335                out[outOfs++] = (byte)(i >> 16);
336                out[outOfs++] = (byte)(i >>  8);
337                out[outOfs++] = (byte)(i      );
338            }
339        }
340    }
341
342    // Store one 32-bit value into out[outOfs..outOfs+3] in big endian order.
343    static void i2bBig4(int val, byte[] out, int outOfs) {
344        if ((outOfs < 0) || ((out.length - outOfs) < 4)) {
345            throw new ArrayIndexOutOfBoundsException();
346        }
347        if (littleEndianUnaligned) {
348            unsafe.putInt(out, (long)(byteArrayOfs + outOfs), reverseBytes(val));
349        } else if (bigEndian && ((outOfs & 3) == 0)) {
350            unsafe.putInt(out, (long)(byteArrayOfs + outOfs), val);
351        } else {
352            out[outOfs    ] = (byte)(val >> 24);
353            out[outOfs + 1] = (byte)(val >> 16);
354            out[outOfs + 2] = (byte)(val >>  8);
355            out[outOfs + 3] = (byte)(val      );
356        }
357    }
358
359    /**
360     * byte[] to long[] conversion, big endian byte order.
361     */
362    static void b2lBig(byte[] in, int inOfs, long[] out, int outOfs, int len) {
363        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
364            (outOfs < 0) || ((out.length - outOfs) < len/8)) {
365            throw new ArrayIndexOutOfBoundsException();
366        }
367        if (littleEndianUnaligned) {
368            inOfs += byteArrayOfs;
369            len += inOfs;
370            while (inOfs < len) {
371                out[outOfs++] = reverseBytes(unsafe.getLong(in, (long)inOfs));
372                inOfs += 8;
373            }
374        } else if (bigEndian && ((inOfs & 3) == 0)) {
375            // In the current HotSpot memory layout, the first element of a
376            // byte[] is only 32-bit aligned, not 64-bit.
377            // That means we could use getLong() only for offset 4, 12, etc.,
378            // which would rarely occur in practice. Instead, we use an
379            // optimization that uses getInt() so that it works for offset 0.
380            inOfs += byteArrayOfs;
381            len += inOfs;
382            while (inOfs < len) {
383                out[outOfs++] =
384                      ((long)unsafe.getInt(in, (long)inOfs) << 32)
385                          | (unsafe.getInt(in, (long)(inOfs + 4)) & 0xffffffffL);
386                inOfs += 8;
387            }
388        } else {
389            len += inOfs;
390            while (inOfs < len) {
391                int i1 = ((in[inOfs + 3] & 0xff)      )
392                       | ((in[inOfs + 2] & 0xff) <<  8)
393                       | ((in[inOfs + 1] & 0xff) << 16)
394                       | ((in[inOfs    ]       ) << 24);
395                inOfs += 4;
396                int i2 = ((in[inOfs + 3] & 0xff)      )
397                       | ((in[inOfs + 2] & 0xff) <<  8)
398                       | ((in[inOfs + 1] & 0xff) << 16)
399                       | ((in[inOfs    ]       ) << 24);
400                out[outOfs++] = ((long)i1 << 32) | (i2 & 0xffffffffL);
401                inOfs += 4;
402            }
403        }
404    }
405
406    // Special optimization of b2lBig(in, inOfs, out, 0, 128)
407    static void b2lBig128(byte[] in, int inOfs, long[] out) {
408        if ((inOfs < 0) || ((in.length - inOfs) < 128) ||
409            (out.length < 16)) {
410            throw new ArrayIndexOutOfBoundsException();
411        }
412        if (littleEndianUnaligned) {
413            inOfs += byteArrayOfs;
414            out[ 0] = reverseBytes(unsafe.getLong(in, (long)(inOfs      )));
415            out[ 1] = reverseBytes(unsafe.getLong(in, (long)(inOfs +   8)));
416            out[ 2] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  16)));
417            out[ 3] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  24)));
418            out[ 4] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  32)));
419            out[ 5] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  40)));
420            out[ 6] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  48)));
421            out[ 7] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  56)));
422            out[ 8] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  64)));
423            out[ 9] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  72)));
424            out[10] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  80)));
425            out[11] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  88)));
426            out[12] = reverseBytes(unsafe.getLong(in, (long)(inOfs +  96)));
427            out[13] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 104)));
428            out[14] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 112)));
429            out[15] = reverseBytes(unsafe.getLong(in, (long)(inOfs + 120)));
430        } else {
431            // no optimization for big endian, see comments in b2lBig
432            b2lBig(in, inOfs, out, 0, 128);
433        }
434    }
435
436    /**
437     * long[] to byte[] conversion, big endian byte order.
438     */
439    static void l2bBig(long[] in, int inOfs, byte[] out, int outOfs, int len) {
440        if ((inOfs < 0) || ((in.length - inOfs) < len/8) ||
441            (outOfs < 0) || ((out.length - outOfs) < len)) {
442            throw new ArrayIndexOutOfBoundsException();
443        }
444        if (littleEndianUnaligned) {
445            outOfs += byteArrayOfs;
446            len += outOfs;
447            while (outOfs < len) {
448                unsafe.putLong(out, (long)outOfs, reverseBytes(in[inOfs++]));
449                outOfs += 8;
450            }
451        } else {
452            len += outOfs;
453            while (outOfs < len) {
454                long i = in[inOfs++];
455                out[outOfs++] = (byte)(i >> 56);
456                out[outOfs++] = (byte)(i >> 48);
457                out[outOfs++] = (byte)(i >> 40);
458                out[outOfs++] = (byte)(i >> 32);
459                out[outOfs++] = (byte)(i >> 24);
460                out[outOfs++] = (byte)(i >> 16);
461                out[outOfs++] = (byte)(i >>  8);
462                out[outOfs++] = (byte)(i      );
463            }
464        }
465    }
466
467    /**
468     * byte[] to long[] conversion, little endian byte order
469     */
470    static void b2lLittle(byte[] in, int inOfs, long[] out, int outOfs, int len) {
471        if ((inOfs < 0) || ((in.length - inOfs) < len) ||
472            ((outOfs < 0) || (out.length - outOfs) < len/8)) {
473            throw new ArrayIndexOutOfBoundsException();
474        }
475        if (littleEndianUnaligned) {
476            inOfs += byteArrayOfs;
477            len += inOfs;
478            while (inOfs < len) {
479                out[outOfs++] = unsafe.getLong(in, (long)inOfs);
480                inOfs += 8;
481            }
482       } else {
483            len += inOfs;
484            while (inOfs < len) {
485                out[outOfs++] = ((in[inOfs    ] & 0xffL)
486                   | ((in[inOfs + 1] & 0xffL) <<  8)
487                   | ((in[inOfs + 2] & 0xffL) << 16)
488                   | ((in[inOfs + 3] & 0xffL) << 24)
489                   | ((in[inOfs + 4] & 0xffL) << 32)
490                   | ((in[inOfs + 5] & 0xffL) << 40)
491                   | ((in[inOfs + 6] & 0xffL) << 48)
492                   | ((in[inOfs + 7] & 0xffL) << 56));
493                inOfs += 8;
494            }
495        }
496    }
497
498
499    /**
500     * long[] to byte[] conversion, little endian byte order
501     */
502    static void l2bLittle(long[] in, int inOfs, byte[] out, int outOfs, int len) {
503        if ((inOfs < 0) || ((in.length - inOfs) < len/8) ||
504            (outOfs < 0) || ((out.length - outOfs) < len)) {
505            throw new ArrayIndexOutOfBoundsException();
506        }
507        if (littleEndianUnaligned) {
508            outOfs += byteArrayOfs;
509            len += outOfs;
510            while (outOfs < len) {
511                unsafe.putLong(out, (long)outOfs, in[inOfs++]);
512                outOfs += 8;
513            }
514        } else {
515            len += outOfs;
516            while (outOfs < len) {
517                long i = in[inOfs++];
518                out[outOfs++] = (byte)(i      );
519                out[outOfs++] = (byte)(i >>  8);
520                out[outOfs++] = (byte)(i >> 16);
521                out[outOfs++] = (byte)(i >> 24);
522                out[outOfs++] = (byte)(i >> 32);
523                out[outOfs++] = (byte)(i >> 40);
524                out[outOfs++] = (byte)(i >> 48);
525                out[outOfs++] = (byte)(i >> 56);
526            }
527        }
528    }
529}
530