View Javadoc
1   /*
2    * Copyright 2015 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.buffer;
17  
18  import io.netty.util.internal.PlatformDependent;
19  
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.OutputStream;
23  import java.nio.ByteBuffer;
24  import java.nio.ByteOrder;
25  import java.nio.ReadOnlyBufferException;
26  
27  import static io.netty.util.internal.MathUtil.isOutOfBounds;
28  import static io.netty.util.internal.ObjectUtil.checkNotNull;
29  import static io.netty.util.internal.PlatformDependent.BIG_ENDIAN_NATIVE_ORDER;
30  
31  /**
32   * All operations get and set as {@link ByteOrder#BIG_ENDIAN}.
33   */
34  final class UnsafeByteBufUtil {
35      private static final boolean UNALIGNED = PlatformDependent.isUnaligned();
36      private static final byte ZERO = 0;
37      private static final int MAX_HAND_ROLLED_SET_ZERO_BYTES = 64;
38  
39      static byte getByte(long address) {
40          return PlatformDependent.getByte(address);
41      }
42  
43      static short getShort(long address) {
44          if (UNALIGNED) {
45              short v = PlatformDependent.getShort(address);
46              return BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
47          }
48          return (short) (PlatformDependent.getByte(address) << 8 | PlatformDependent.getByte(address + 1) & 0xff);
49      }
50  
51      static short getShortLE(long address) {
52          if (UNALIGNED) {
53              short v = PlatformDependent.getShort(address);
54              return BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(v) : v;
55          }
56          return (short) (PlatformDependent.getByte(address) & 0xff | PlatformDependent.getByte(address + 1) << 8);
57      }
58  
59      static int getUnsignedMedium(long address) {
60          if (UNALIGNED) {
61              return (PlatformDependent.getByte(address) & 0xff) << 16 |
62                      (BIG_ENDIAN_NATIVE_ORDER ? PlatformDependent.getShort(address + 1)
63                                               : Short.reverseBytes(PlatformDependent.getShort(address + 1))) & 0xffff;
64          }
65          return (PlatformDependent.getByte(address)     & 0xff) << 16 |
66                 (PlatformDependent.getByte(address + 1) & 0xff) << 8  |
67                 PlatformDependent.getByte(address + 2)  & 0xff;
68      }
69  
70      static int getUnsignedMediumLE(long address) {
71          if (UNALIGNED) {
72              return (PlatformDependent.getByte(address) & 0xff) |
73                      ((BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(PlatformDependent.getShort(address + 1))
74                                                : PlatformDependent.getShort(address + 1)) & 0xffff) << 8;
75          }
76          return PlatformDependent.getByte(address)      & 0xff        |
77                 (PlatformDependent.getByte(address + 1) & 0xff) << 8  |
78                 (PlatformDependent.getByte(address + 2) & 0xff) << 16;
79      }
80  
81      static int getInt(long address) {
82          if (UNALIGNED) {
83              int v = PlatformDependent.getInt(address);
84              return BIG_ENDIAN_NATIVE_ORDER ? v : Integer.reverseBytes(v);
85          }
86          return PlatformDependent.getByte(address) << 24 |
87                 (PlatformDependent.getByte(address + 1) & 0xff) << 16 |
88                 (PlatformDependent.getByte(address + 2) & 0xff) <<  8 |
89                 PlatformDependent.getByte(address + 3)  & 0xff;
90      }
91  
92      static int getIntLE(long address) {
93          if (UNALIGNED) {
94              int v = PlatformDependent.getInt(address);
95              return BIG_ENDIAN_NATIVE_ORDER ? Integer.reverseBytes(v) : v;
96          }
97          return PlatformDependent.getByte(address) & 0xff |
98                 (PlatformDependent.getByte(address + 1) & 0xff) <<  8 |
99                 (PlatformDependent.getByte(address + 2) & 0xff) << 16 |
100                PlatformDependent.getByte(address + 3) << 24;
101     }
102 
103     static long getLong(long address) {
104         if (UNALIGNED) {
105             long v = PlatformDependent.getLong(address);
106             return BIG_ENDIAN_NATIVE_ORDER ? v : Long.reverseBytes(v);
107         }
108         return ((long) PlatformDependent.getByte(address)) << 56 |
109                (PlatformDependent.getByte(address + 1) & 0xffL) << 48 |
110                (PlatformDependent.getByte(address + 2) & 0xffL) << 40 |
111                (PlatformDependent.getByte(address + 3) & 0xffL) << 32 |
112                (PlatformDependent.getByte(address + 4) & 0xffL) << 24 |
113                (PlatformDependent.getByte(address + 5) & 0xffL) << 16 |
114                (PlatformDependent.getByte(address + 6) & 0xffL) <<  8 |
115                (PlatformDependent.getByte(address + 7)) & 0xffL;
116     }
117 
118     static long getLongLE(long address) {
119         if (UNALIGNED) {
120             long v = PlatformDependent.getLong(address);
121             return BIG_ENDIAN_NATIVE_ORDER ? Long.reverseBytes(v) : v;
122         }
123         return (PlatformDependent.getByte(address))    & 0xffL        |
124                (PlatformDependent.getByte(address + 1) & 0xffL) <<  8 |
125                (PlatformDependent.getByte(address + 2) & 0xffL) << 16 |
126                (PlatformDependent.getByte(address + 3) & 0xffL) << 24 |
127                (PlatformDependent.getByte(address + 4) & 0xffL) << 32 |
128                (PlatformDependent.getByte(address + 5) & 0xffL) << 40 |
129                (PlatformDependent.getByte(address + 6) & 0xffL) << 48 |
130                ((long) PlatformDependent.getByte(address + 7))  << 56;
131     }
132 
133     static void setByte(long address, int value) {
134         PlatformDependent.putByte(address, (byte) value);
135     }
136 
137     static void setShort(long address, int value) {
138         if (UNALIGNED) {
139             PlatformDependent.putShort(
140                     address, BIG_ENDIAN_NATIVE_ORDER ? (short) value : Short.reverseBytes((short) value));
141         } else {
142             PlatformDependent.putByte(address, (byte) (value >>> 8));
143             PlatformDependent.putByte(address + 1, (byte) value);
144         }
145     }
146 
147     static void setShortLE(long address, int value) {
148         if (UNALIGNED) {
149             PlatformDependent.putShort(
150                 address, BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes((short) value) : (short) value);
151         } else {
152             PlatformDependent.putByte(address, (byte) value);
153             PlatformDependent.putByte(address + 1, (byte) (value >>> 8));
154         }
155     }
156 
157     static void setMedium(long address, int value) {
158         PlatformDependent.putByte(address, (byte) (value >>> 16));
159         if (UNALIGNED) {
160             PlatformDependent.putShort(address + 1, BIG_ENDIAN_NATIVE_ORDER ? (short) value
161                                                                             : Short.reverseBytes((short) value));
162         } else {
163             PlatformDependent.putByte(address + 1, (byte) (value >>> 8));
164             PlatformDependent.putByte(address + 2, (byte) value);
165         }
166     }
167 
168     static void setMediumLE(long address, int value) {
169         PlatformDependent.putByte(address, (byte) value);
170         if (UNALIGNED) {
171             PlatformDependent.putShort(address + 1, BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes((short) (value >>> 8))
172                                                                             : (short) (value >>> 8));
173         } else {
174             PlatformDependent.putByte(address + 1, (byte) (value >>> 8));
175             PlatformDependent.putByte(address + 2, (byte) (value >>> 16));
176         }
177     }
178 
179     static void setInt(long address, int value) {
180         if (UNALIGNED) {
181             PlatformDependent.putInt(address, BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
182         } else {
183             PlatformDependent.putByte(address, (byte) (value >>> 24));
184             PlatformDependent.putByte(address + 1, (byte) (value >>> 16));
185             PlatformDependent.putByte(address + 2, (byte) (value >>> 8));
186             PlatformDependent.putByte(address + 3, (byte) value);
187         }
188     }
189 
190     static void setIntLE(long address, int value) {
191         if (UNALIGNED) {
192             PlatformDependent.putInt(address, BIG_ENDIAN_NATIVE_ORDER ? Integer.reverseBytes(value) : value);
193         } else {
194             PlatformDependent.putByte(address, (byte) value);
195             PlatformDependent.putByte(address + 1, (byte) (value >>> 8));
196             PlatformDependent.putByte(address + 2, (byte) (value >>> 16));
197             PlatformDependent.putByte(address + 3, (byte) (value >>> 24));
198         }
199     }
200 
201     static void setLong(long address, long value) {
202         if (UNALIGNED) {
203             PlatformDependent.putLong(address, BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
204         } else {
205             PlatformDependent.putByte(address, (byte) (value >>> 56));
206             PlatformDependent.putByte(address + 1, (byte) (value >>> 48));
207             PlatformDependent.putByte(address + 2, (byte) (value >>> 40));
208             PlatformDependent.putByte(address + 3, (byte) (value >>> 32));
209             PlatformDependent.putByte(address + 4, (byte) (value >>> 24));
210             PlatformDependent.putByte(address + 5, (byte) (value >>> 16));
211             PlatformDependent.putByte(address + 6, (byte) (value >>> 8));
212             PlatformDependent.putByte(address + 7, (byte) value);
213         }
214     }
215 
216     static void setLongLE(long address, long value) {
217         if (UNALIGNED) {
218             PlatformDependent.putLong(address, BIG_ENDIAN_NATIVE_ORDER ? Long.reverseBytes(value) : value);
219         } else {
220             PlatformDependent.putByte(address, (byte) value);
221             PlatformDependent.putByte(address + 1, (byte) (value >>> 8));
222             PlatformDependent.putByte(address + 2, (byte) (value >>> 16));
223             PlatformDependent.putByte(address + 3, (byte) (value >>> 24));
224             PlatformDependent.putByte(address + 4, (byte) (value >>> 32));
225             PlatformDependent.putByte(address + 5, (byte) (value >>> 40));
226             PlatformDependent.putByte(address + 6, (byte) (value >>> 48));
227             PlatformDependent.putByte(address + 7, (byte) (value >>> 56));
228         }
229     }
230 
231     static byte getByte(byte[] array, int index) {
232         return PlatformDependent.getByte(array, index);
233     }
234 
235     static short getShort(byte[] array, int index) {
236         if (UNALIGNED) {
237             short v = PlatformDependent.getShort(array, index);
238             return BIG_ENDIAN_NATIVE_ORDER ? v : Short.reverseBytes(v);
239         }
240         return (short) (PlatformDependent.getByte(array, index) << 8 |
241                        PlatformDependent.getByte(array, index + 1) & 0xff);
242     }
243 
244     static short getShortLE(byte[] array, int index) {
245         if (UNALIGNED) {
246             short v = PlatformDependent.getShort(array, index);
247             return BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(v) : v;
248         }
249         return (short) (PlatformDependent.getByte(array, index) & 0xff |
250                        PlatformDependent.getByte(array, index + 1) << 8);
251     }
252 
253     static int getUnsignedMedium(byte[] array, int index) {
254         if (UNALIGNED) {
255             return (PlatformDependent.getByte(array, index) & 0xff) << 16 |
256                     (BIG_ENDIAN_NATIVE_ORDER ? PlatformDependent.getShort(array, index + 1)
257                                              : Short.reverseBytes(PlatformDependent.getShort(array, index + 1)))
258                             & 0xffff;
259         }
260         return (PlatformDependent.getByte(array, index) & 0xff) << 16 |
261                (PlatformDependent.getByte(array, index + 1) & 0xff) <<  8 |
262                PlatformDependent.getByte(array, index + 2) & 0xff;
263     }
264 
265     static int getUnsignedMediumLE(byte[] array, int index) {
266         if (UNALIGNED) {
267             return (PlatformDependent.getByte(array, index) & 0xff) |
268                     ((BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes(PlatformDependent.getShort(array, index + 1))
269                                               : PlatformDependent.getShort(array, index + 1)) & 0xffff) << 8;
270         }
271         return PlatformDependent.getByte(array, index) & 0xff |
272                (PlatformDependent.getByte(array, index + 1) & 0xff) <<  8 |
273                (PlatformDependent.getByte(array, index + 2) & 0xff) << 16;
274     }
275 
276     static int getInt(byte[] array, int index) {
277         if (UNALIGNED) {
278             int v = PlatformDependent.getInt(array, index);
279             return BIG_ENDIAN_NATIVE_ORDER ? v : Integer.reverseBytes(v);
280         }
281         return PlatformDependent.getByte(array, index) << 24 |
282                (PlatformDependent.getByte(array, index + 1) & 0xff) << 16 |
283                (PlatformDependent.getByte(array, index + 2) & 0xff) <<  8 |
284                PlatformDependent.getByte(array, index + 3) & 0xff;
285     }
286 
287     static int getIntLE(byte[] array, int index) {
288         if (UNALIGNED) {
289             int v = PlatformDependent.getInt(array, index);
290             return BIG_ENDIAN_NATIVE_ORDER ? Integer.reverseBytes(v) : v;
291         }
292         return PlatformDependent.getByte(array, index)      & 0xff        |
293                (PlatformDependent.getByte(array, index + 1) & 0xff) <<  8 |
294                (PlatformDependent.getByte(array, index + 2) & 0xff) << 16 |
295                PlatformDependent.getByte(array,  index + 3) << 24;
296     }
297 
298     static long getLong(byte[] array, int index) {
299         if (UNALIGNED) {
300             long v = PlatformDependent.getLong(array, index);
301             return BIG_ENDIAN_NATIVE_ORDER ? v : Long.reverseBytes(v);
302         }
303         return ((long) PlatformDependent.getByte(array, index)) << 56 |
304                (PlatformDependent.getByte(array, index + 1) & 0xffL) << 48 |
305                (PlatformDependent.getByte(array, index + 2) & 0xffL) << 40 |
306                (PlatformDependent.getByte(array, index + 3) & 0xffL) << 32 |
307                (PlatformDependent.getByte(array, index + 4) & 0xffL) << 24 |
308                (PlatformDependent.getByte(array, index + 5) & 0xffL) << 16 |
309                (PlatformDependent.getByte(array, index + 6) & 0xffL) <<  8 |
310                (PlatformDependent.getByte(array, index + 7)) & 0xffL;
311     }
312 
313     static long getLongLE(byte[] array, int index) {
314         if (UNALIGNED) {
315             long v = PlatformDependent.getLong(array, index);
316             return BIG_ENDIAN_NATIVE_ORDER ? Long.reverseBytes(v) : v;
317         }
318         return PlatformDependent.getByte(array, index)      & 0xffL        |
319                (PlatformDependent.getByte(array, index + 1) & 0xffL) <<  8 |
320                (PlatformDependent.getByte(array, index + 2) & 0xffL) << 16 |
321                (PlatformDependent.getByte(array, index + 3) & 0xffL) << 24 |
322                (PlatformDependent.getByte(array, index + 4) & 0xffL) << 32 |
323                (PlatformDependent.getByte(array, index + 5) & 0xffL) << 40 |
324                (PlatformDependent.getByte(array, index + 6) & 0xffL) << 48 |
325                ((long) PlatformDependent.getByte(array,  index + 7)) << 56;
326     }
327 
328     static void setByte(byte[] array, int index, int value) {
329         PlatformDependent.putByte(array, index, (byte) value);
330     }
331 
332     static void setShort(byte[] array, int index, int value) {
333         if (UNALIGNED) {
334             PlatformDependent.putShort(array, index,
335                                        BIG_ENDIAN_NATIVE_ORDER ? (short) value : Short.reverseBytes((short) value));
336         } else {
337             PlatformDependent.putByte(array, index, (byte) (value >>> 8));
338             PlatformDependent.putByte(array, index + 1, (byte) value);
339         }
340     }
341 
342     static void setShortLE(byte[] array, int index, int value) {
343         if (UNALIGNED) {
344             PlatformDependent.putShort(array, index,
345                                        BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes((short) value) : (short) value);
346         } else {
347             PlatformDependent.putByte(array, index, (byte) value);
348             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 8));
349         }
350     }
351 
352     static void setMedium(byte[] array, int index, int value) {
353         PlatformDependent.putByte(array, index, (byte) (value >>> 16));
354         if (UNALIGNED) {
355                 PlatformDependent.putShort(array, index + 1,
356                                            BIG_ENDIAN_NATIVE_ORDER ? (short) value
357                                                                    : Short.reverseBytes((short) value));
358         } else {
359             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 8));
360             PlatformDependent.putByte(array, index + 2, (byte) value);
361         }
362     }
363 
364     static void setMediumLE(byte[] array, int index, int value) {
365         PlatformDependent.putByte(array, index, (byte) value);
366         if (UNALIGNED) {
367             PlatformDependent.putShort(array, index + 1,
368                                        BIG_ENDIAN_NATIVE_ORDER ? Short.reverseBytes((short) (value >>> 8))
369                                                                : (short) (value >>> 8));
370         } else {
371             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 8));
372             PlatformDependent.putByte(array, index + 2, (byte) (value >>> 16));
373         }
374     }
375 
376     static void setInt(byte[] array, int index, int value) {
377         if (UNALIGNED) {
378             PlatformDependent.putInt(array, index, BIG_ENDIAN_NATIVE_ORDER ? value : Integer.reverseBytes(value));
379         } else {
380             PlatformDependent.putByte(array, index, (byte) (value >>> 24));
381             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 16));
382             PlatformDependent.putByte(array, index + 2, (byte) (value >>> 8));
383             PlatformDependent.putByte(array, index + 3, (byte) value);
384         }
385     }
386 
387     static void setIntLE(byte[] array, int index, int value) {
388         if (UNALIGNED) {
389             PlatformDependent.putInt(array, index, BIG_ENDIAN_NATIVE_ORDER ? Integer.reverseBytes(value) : value);
390         } else {
391             PlatformDependent.putByte(array, index, (byte) value);
392             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 8));
393             PlatformDependent.putByte(array, index + 2, (byte) (value >>> 16));
394             PlatformDependent.putByte(array, index + 3, (byte) (value >>> 24));
395         }
396     }
397 
398     static void setLong(byte[] array, int index, long value) {
399         if (UNALIGNED) {
400             PlatformDependent.putLong(array, index, BIG_ENDIAN_NATIVE_ORDER ? value : Long.reverseBytes(value));
401         } else {
402             PlatformDependent.putByte(array, index, (byte) (value >>> 56));
403             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 48));
404             PlatformDependent.putByte(array, index + 2, (byte) (value >>> 40));
405             PlatformDependent.putByte(array, index + 3, (byte) (value >>> 32));
406             PlatformDependent.putByte(array, index + 4, (byte) (value >>> 24));
407             PlatformDependent.putByte(array, index + 5, (byte) (value >>> 16));
408             PlatformDependent.putByte(array, index + 6, (byte) (value >>> 8));
409             PlatformDependent.putByte(array, index + 7, (byte) value);
410         }
411     }
412 
413     static void setLongLE(byte[] array, int index, long value) {
414         if (UNALIGNED) {
415             PlatformDependent.putLong(array, index, BIG_ENDIAN_NATIVE_ORDER ? Long.reverseBytes(value) : value);
416         } else {
417             PlatformDependent.putByte(array, index, (byte) value);
418             PlatformDependent.putByte(array, index + 1, (byte) (value >>> 8));
419             PlatformDependent.putByte(array, index + 2, (byte) (value >>> 16));
420             PlatformDependent.putByte(array, index + 3, (byte) (value >>> 24));
421             PlatformDependent.putByte(array, index + 4, (byte) (value >>> 32));
422             PlatformDependent.putByte(array, index + 5, (byte) (value >>> 40));
423             PlatformDependent.putByte(array, index + 6, (byte) (value >>> 48));
424             PlatformDependent.putByte(array, index + 7, (byte) (value >>> 56));
425         }
426     }
427 
428     private static void batchSetZero(byte[] data, int index, int length) {
429         int longBatches = length / 8;
430         for (int i = 0; i < longBatches; i++) {
431             PlatformDependent.putLong(data, index, ZERO);
432             index += 8;
433         }
434         final int remaining = length % 8;
435         for (int i = 0; i < remaining; i++) {
436             PlatformDependent.putByte(data, index + i, ZERO);
437         }
438     }
439 
440     static void setZero(byte[] array, int index, int length) {
441         if (length == 0) {
442             return;
443         }
444         // fast-path for small writes to avoid thread-state change JDK's handling
445         if (UNALIGNED && length <= MAX_HAND_ROLLED_SET_ZERO_BYTES) {
446             batchSetZero(array, index, length);
447         } else {
448             PlatformDependent.setMemory(array, index, length, ZERO);
449         }
450     }
451 
452     static ByteBuf copy(AbstractByteBuf buf, long addr, int index, int length) {
453         buf.checkIndex(index, length);
454         ByteBuf copy = buf.alloc().directBuffer(length, buf.maxCapacity());
455         if (length != 0) {
456             if (copy.hasMemoryAddress()) {
457                 PlatformDependent.copyMemory(addr, copy.memoryAddress(), length);
458                 copy.setIndex(0, length);
459             } else {
460                 copy.writeBytes(buf, index, length);
461             }
462         }
463         return copy;
464     }
465 
466     static int setBytes(AbstractByteBuf buf, long addr, int index, InputStream in, int length) throws IOException {
467         buf.checkIndex(index, length);
468         ByteBuf tmpBuf = buf.alloc().heapBuffer(length);
469         try {
470             byte[] tmp = tmpBuf.array();
471             int offset = tmpBuf.arrayOffset();
472             int readBytes = in.read(tmp, offset, length);
473             if (readBytes > 0) {
474                 PlatformDependent.copyMemory(tmp, offset, addr, readBytes);
475             }
476             return readBytes;
477         } finally {
478             tmpBuf.release();
479         }
480     }
481 
482     static void getBytes(AbstractByteBuf buf, long addr, int index, ByteBuf dst, int dstIndex, int length) {
483         buf.checkIndex(index, length);
484         checkNotNull(dst, "dst");
485         if (isOutOfBounds(dstIndex, length, dst.capacity())) {
486             throw new IndexOutOfBoundsException("dstIndex: " + dstIndex);
487         }
488 
489         if (dst.hasMemoryAddress()) {
490             PlatformDependent.copyMemory(addr, dst.memoryAddress() + dstIndex, length);
491         } else if (dst.hasArray()) {
492             PlatformDependent.copyMemory(addr, dst.array(), dst.arrayOffset() + dstIndex, length);
493         } else {
494             dst.setBytes(dstIndex, buf, index, length);
495         }
496     }
497 
498     static void getBytes(AbstractByteBuf buf, long addr, int index, byte[] dst, int dstIndex, int length) {
499         buf.checkIndex(index, length);
500         checkNotNull(dst, "dst");
501         if (isOutOfBounds(dstIndex, length, dst.length)) {
502             throw new IndexOutOfBoundsException("dstIndex: " + dstIndex);
503         }
504         if (length != 0) {
505             PlatformDependent.copyMemory(addr, dst, dstIndex, length);
506         }
507     }
508 
509     static void getBytes(AbstractByteBuf buf, long addr, int index, ByteBuffer dst) {
510         buf.checkIndex(index, dst.remaining());
511         if (dst.remaining() == 0) {
512             return;
513         }
514 
515         if (dst.isDirect()) {
516             if (dst.isReadOnly()) {
517                 // We need to check if dst is ready-only so we not write something in it by using Unsafe.
518                 throw new ReadOnlyBufferException();
519             }
520             // Copy to direct memory
521             long dstAddress = PlatformDependent.directBufferAddress(dst);
522             PlatformDependent.copyMemory(addr, dstAddress + dst.position(), dst.remaining());
523             dst.position(dst.position() + dst.remaining());
524         } else if (dst.hasArray()) {
525             // Copy to array
526             PlatformDependent.copyMemory(addr, dst.array(), dst.arrayOffset() + dst.position(), dst.remaining());
527             dst.position(dst.position() + dst.remaining());
528         } else  {
529             dst.put(buf.nioBuffer());
530         }
531     }
532 
533     static void setBytes(AbstractByteBuf buf, long addr, int index, ByteBuf src, int srcIndex, int length) {
534         buf.checkIndex(index, length);
535         checkNotNull(src, "src");
536         if (isOutOfBounds(srcIndex, length, src.capacity())) {
537             throw new IndexOutOfBoundsException("srcIndex: " + srcIndex);
538         }
539 
540         if (length != 0) {
541             if (src.hasMemoryAddress()) {
542                 PlatformDependent.copyMemory(src.memoryAddress() + srcIndex, addr, length);
543             } else if (src.hasArray()) {
544                 PlatformDependent.copyMemory(src.array(), src.arrayOffset() + srcIndex, addr, length);
545             } else {
546                 src.getBytes(srcIndex, buf, index, length);
547             }
548         }
549     }
550 
551     static void setBytes(AbstractByteBuf buf, long addr, int index, byte[] src, int srcIndex, int length) {
552         buf.checkIndex(index, length);
553         // we need to check not null for src as it may cause the JVM crash
554         // See https://github.com/netty/netty/issues/10791
555         checkNotNull(src, "src");
556         if (isOutOfBounds(srcIndex, length, src.length)) {
557             throw new IndexOutOfBoundsException("srcIndex: " + srcIndex);
558         }
559 
560         if (length != 0) {
561             PlatformDependent.copyMemory(src, srcIndex, addr, length);
562         }
563     }
564 
565     static void setBytes(AbstractByteBuf buf, long addr, int index, ByteBuffer src) {
566         final int length = src.remaining();
567         if (length == 0) {
568             return;
569         }
570 
571         if (src.isDirect()) {
572             buf.checkIndex(index, length);
573             // Copy from direct memory
574             long srcAddress = PlatformDependent.directBufferAddress(src);
575             PlatformDependent.copyMemory(srcAddress + src.position(), addr, length);
576             src.position(src.position() + length);
577         } else if (src.hasArray()) {
578             buf.checkIndex(index, length);
579             // Copy from array
580             PlatformDependent.copyMemory(src.array(), src.arrayOffset() + src.position(), addr, length);
581             src.position(src.position() + length);
582         } else {
583             if (length < 8) {
584                 setSingleBytes(buf, addr, index, src, length);
585             } else {
586                 //no need to checkIndex: internalNioBuffer is already taking care of it
587                 assert buf.nioBufferCount() == 1;
588                 final ByteBuffer internalBuffer = buf.internalNioBuffer(index, length);
589                 internalBuffer.put(src);
590             }
591         }
592     }
593 
594     private static void setSingleBytes(final AbstractByteBuf buf, final long addr, final int index,
595                                        final ByteBuffer src, final int length) {
596         buf.checkIndex(index, length);
597         final int srcPosition = src.position();
598         final int srcLimit = src.limit();
599         long dstAddr = addr;
600         for (int srcIndex = srcPosition; srcIndex < srcLimit; srcIndex++) {
601             final byte value = src.get(srcIndex);
602             PlatformDependent.putByte(dstAddr, value);
603             dstAddr++;
604         }
605         src.position(srcLimit);
606     }
607 
608     static void getBytes(AbstractByteBuf buf, long addr, int index, OutputStream out, int length) throws IOException {
609         buf.checkIndex(index, length);
610         if (length != 0) {
611             int len = Math.min(length, ByteBufUtil.WRITE_CHUNK_SIZE);
612             if (len <= ByteBufUtil.MAX_TL_ARRAY_LEN || !buf.alloc().isDirectBufferPooled()) {
613                 getBytes(addr, ByteBufUtil.threadLocalTempArray(len), 0, len, out, length);
614             } else {
615                 // if direct buffers are pooled chances are good that heap buffers are pooled as well.
616                 ByteBuf tmpBuf = buf.alloc().heapBuffer(len);
617                 try {
618                     byte[] tmp = tmpBuf.array();
619                     int offset = tmpBuf.arrayOffset();
620                     getBytes(addr, tmp, offset, len, out, length);
621                 } finally {
622                     tmpBuf.release();
623                 }
624             }
625         }
626     }
627 
628     private static void getBytes(long inAddr, byte[] in, int inOffset, int inLen, OutputStream out, int outLen)
629             throws IOException {
630         do {
631             int len = Math.min(inLen, outLen);
632             PlatformDependent.copyMemory(inAddr, in, inOffset, len);
633             out.write(in, inOffset, len);
634             outLen -= len;
635             inAddr += len;
636         } while (outLen > 0);
637     }
638 
639     private static void batchSetZero(long addr, int length) {
640         int longBatches = length / 8;
641         for (int i = 0; i < longBatches; i++) {
642             PlatformDependent.putLong(addr, ZERO);
643             addr += 8;
644         }
645         final int remaining = length % 8;
646         for (int i = 0; i < remaining; i++) {
647             PlatformDependent.putByte(addr + i, ZERO);
648         }
649     }
650 
651     static void setZero(long addr, int length) {
652         if (length == 0) {
653             return;
654         }
655         // fast-path for small writes to avoid thread-state change JDK's handling
656         if (length <= MAX_HAND_ROLLED_SET_ZERO_BYTES) {
657             if (!UNALIGNED) {
658                 // write bytes until the address is aligned
659                 int bytesToGetAligned = zeroTillAligned(addr, length);
660                 addr += bytesToGetAligned;
661                 length -= bytesToGetAligned;
662                 if (length == 0) {
663                     return;
664                 }
665                 assert addr % 8 == 0;
666             }
667             batchSetZero(addr, length);
668         } else {
669             PlatformDependent.setMemory(addr, length, ZERO);
670         }
671     }
672 
673     private static int zeroTillAligned(long addr, int length) {
674         // write bytes until the address is aligned
675         int bytesToGetAligned = Math.min((int) (addr % 8), length);
676         for (int i = 0; i < bytesToGetAligned; i++) {
677             PlatformDependent.putByte(addr + i, ZERO);
678         }
679         return bytesToGetAligned;
680     }
681 
682     static UnpooledUnsafeDirectByteBuf newUnsafeDirectByteBuf(
683             ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
684         if (PlatformDependent.useDirectBufferNoCleaner()) {
685             return new UnpooledUnsafeNoCleanerDirectByteBuf(alloc, initialCapacity, maxCapacity);
686         }
687         return new UnpooledUnsafeDirectByteBuf(alloc, initialCapacity, maxCapacity);
688     }
689 
690     private UnsafeByteBufUtil() { }
691 }