View Javadoc
1   /*
2    * Copyright 2012 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.CleanableDirectBuffer;
19  import io.netty.util.internal.ObjectUtil;
20  import io.netty.util.internal.PlatformDependent;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.nio.ByteBuffer;
26  import java.nio.ByteOrder;
27  import java.nio.channels.ClosedChannelException;
28  import java.nio.channels.FileChannel;
29  import java.nio.channels.GatheringByteChannel;
30  import java.nio.channels.ScatteringByteChannel;
31  
32  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
33  
34  /**
35   * A NIO {@link ByteBuffer} based buffer. It is recommended to use
36   * {@link UnpooledByteBufAllocator#directBuffer(int, int)}, {@link Unpooled#directBuffer(int)} and
37   * {@link Unpooled#wrappedBuffer(ByteBuffer)} instead of calling the constructor explicitly.
38   */
39  public class UnpooledDirectByteBuf extends AbstractReferenceCountedByteBuf {
40  
41      private final ByteBufAllocator alloc;
42  
43      CleanableDirectBuffer cleanable;
44      ByteBuffer buffer; // accessed by UnpooledUnsafeNoCleanerDirectByteBuf.reallocateDirect()
45      private ByteBuffer tmpNioBuf;
46      private int capacity;
47      private boolean doNotFree;
48  
49      /**
50       * Creates a new direct buffer.
51       *
52       * @param initialCapacity the initial capacity of the underlying direct buffer
53       * @param maxCapacity     the maximum capacity of the underlying direct buffer
54       */
55      public UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
56          this(alloc, initialCapacity, maxCapacity, false);
57      }
58  
59      UnpooledDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity, boolean permitExpensiveClean) {
60          super(maxCapacity);
61          ObjectUtil.checkNotNull(alloc, "alloc");
62          checkPositiveOrZero(initialCapacity, "initialCapacity");
63          checkPositiveOrZero(maxCapacity, "maxCapacity");
64          if (initialCapacity > maxCapacity) {
65              throw new IllegalArgumentException(String.format(
66                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
67          }
68  
69          this.alloc = alloc;
70          setByteBuffer(allocateDirectBuffer(initialCapacity, permitExpensiveClean), false);
71      }
72  
73      /**
74       * Creates a new direct buffer by wrapping the specified initial buffer.
75       *
76       * @param maxCapacity the maximum capacity of the underlying direct buffer
77       */
78      protected UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer, int maxCapacity) {
79          this(alloc, initialBuffer, maxCapacity, false, true);
80      }
81  
82      UnpooledDirectByteBuf(ByteBufAllocator alloc, ByteBuffer initialBuffer,
83              int maxCapacity, boolean doFree, boolean slice) {
84          super(maxCapacity);
85          ObjectUtil.checkNotNull(alloc, "alloc");
86          ObjectUtil.checkNotNull(initialBuffer, "initialBuffer");
87          if (!initialBuffer.isDirect()) {
88              throw new IllegalArgumentException("initialBuffer is not a direct buffer.");
89          }
90          if (initialBuffer.isReadOnly()) {
91              throw new IllegalArgumentException("initialBuffer is a read-only buffer.");
92          }
93  
94          int initialCapacity = initialBuffer.remaining();
95          if (initialCapacity > maxCapacity) {
96              throw new IllegalArgumentException(String.format(
97                      "initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
98          }
99  
100         this.alloc = alloc;
101         doNotFree = !doFree;
102         setByteBuffer((slice ? initialBuffer.slice() : initialBuffer).order(ByteOrder.BIG_ENDIAN), false);
103         writerIndex(initialCapacity);
104     }
105 
106     /**
107      * Allocate a new direct {@link ByteBuffer} with the given initialCapacity.
108      * @deprecated Use {@link #allocateDirectBuffer(int)} instead.
109      */
110     @Deprecated
111     protected ByteBuffer allocateDirect(int initialCapacity) {
112         return ByteBuffer.allocateDirect(initialCapacity);
113     }
114 
115     /**
116      * Free a direct {@link ByteBuffer}
117      * @deprecated Use {@link #allocateDirectBuffer(int)} instead.
118      */
119     @Deprecated
120     protected void freeDirect(ByteBuffer buffer) {
121         PlatformDependent.freeDirectBuffer(buffer);
122     }
123 
124     protected CleanableDirectBuffer allocateDirectBuffer(int capacity) {
125         return PlatformDependent.allocateDirect(capacity, false);
126     }
127 
128     CleanableDirectBuffer allocateDirectBuffer(int capacity, boolean permitExpensiveClean) {
129         return PlatformDependent.allocateDirect(capacity, permitExpensiveClean);
130     }
131 
132     void setByteBuffer(CleanableDirectBuffer cleanableDirectBuffer, boolean tryFree) {
133         if (tryFree) {
134             CleanableDirectBuffer oldCleanable = cleanable;
135             ByteBuffer oldBuffer = buffer;
136             if (oldBuffer != null) {
137                 if (doNotFree) {
138                     doNotFree = false;
139                 } else {
140                     if (oldCleanable != null) {
141                         oldCleanable.clean();
142                     } else {
143                         freeDirect(oldBuffer);
144                     }
145                 }
146             }
147         }
148 
149         cleanable = cleanableDirectBuffer;
150         buffer = cleanableDirectBuffer.buffer();
151         tmpNioBuf = null;
152         capacity = buffer.remaining();
153     }
154 
155     void setByteBuffer(ByteBuffer buffer, boolean tryFree) {
156         if (tryFree) {
157             ByteBuffer oldBuffer = this.buffer;
158             if (oldBuffer != null) {
159                 if (doNotFree) {
160                     doNotFree = false;
161                 } else {
162                     freeDirect(oldBuffer);
163                 }
164             }
165         }
166 
167         this.buffer = buffer;
168         tmpNioBuf = null;
169         capacity = buffer.remaining();
170     }
171 
172     @Override
173     public boolean isDirect() {
174         return true;
175     }
176 
177     @Override
178     public int capacity() {
179         return capacity;
180     }
181 
182     @Override
183     public ByteBuf capacity(int newCapacity) {
184         checkNewCapacity(newCapacity);
185         int oldCapacity = capacity;
186         if (newCapacity == oldCapacity) {
187             return this;
188         }
189         int bytesToCopy;
190         if (newCapacity > oldCapacity) {
191             bytesToCopy = oldCapacity;
192         } else {
193             trimIndicesToCapacity(newCapacity);
194             bytesToCopy = newCapacity;
195         }
196         ByteBuffer oldBuffer = buffer;
197         CleanableDirectBuffer newBuffer = allocateDirectBuffer(newCapacity);
198         oldBuffer.position(0).limit(bytesToCopy);
199         newBuffer.buffer().position(0).limit(bytesToCopy);
200         newBuffer.buffer().put(oldBuffer).clear();
201         setByteBuffer(newBuffer, true);
202         return this;
203     }
204 
205     @Override
206     public ByteBufAllocator alloc() {
207         return alloc;
208     }
209 
210     @Override
211     public ByteOrder order() {
212         return ByteOrder.BIG_ENDIAN;
213     }
214 
215     @Override
216     public boolean hasArray() {
217         return false;
218     }
219 
220     @Override
221     public byte[] array() {
222         throw new UnsupportedOperationException("direct buffer");
223     }
224 
225     @Override
226     public int arrayOffset() {
227         throw new UnsupportedOperationException("direct buffer");
228     }
229 
230     @Override
231     public boolean hasMemoryAddress() {
232         CleanableDirectBuffer cleanable = this.cleanable;
233         return cleanable != null && cleanable.hasMemoryAddress();
234     }
235 
236     @Override
237     public long memoryAddress() {
238         ensureAccessible();
239         if (!hasMemoryAddress()) {
240             throw new UnsupportedOperationException();
241         }
242         return cleanable.memoryAddress();
243     }
244 
245     @Override
246     public byte getByte(int index) {
247         ensureAccessible();
248         return _getByte(index);
249     }
250 
251     @Override
252     protected byte _getByte(int index) {
253         return buffer.get(index);
254     }
255 
256     @Override
257     public short getShortLE(int index) {
258         ensureAccessible();
259         return _getShortLE(index);
260     }
261 
262     @Override
263     public short getShort(int index) {
264         ensureAccessible();
265         return _getShort(index);
266     }
267 
268     @Override
269     protected short _getShort(int index) {
270         if (PlatformDependent.hasVarHandle()) {
271             return VarHandleByteBufferAccess.getShortBE(buffer, index);
272         }
273         return buffer.getShort(index);
274     }
275 
276     @Override
277     protected short _getShortLE(int index) {
278         if (PlatformDependent.hasVarHandle()) {
279             return VarHandleByteBufferAccess.getShortLE(buffer, index);
280         }
281         return ByteBufUtil.swapShort(buffer.getShort(index));
282     }
283 
284     @Override
285     public int getUnsignedMedium(int index) {
286         ensureAccessible();
287         return _getUnsignedMedium(index);
288     }
289 
290     @Override
291     protected int _getUnsignedMedium(int index) {
292         return (getByte(index) & 0xff)     << 16 |
293                (getByte(index + 1) & 0xff) << 8  |
294                getByte(index + 2) & 0xff;
295     }
296 
297     @Override
298     protected int _getUnsignedMediumLE(int index) {
299         return getByte(index) & 0xff             |
300                (getByte(index + 1) & 0xff) << 8  |
301                (getByte(index + 2) & 0xff) << 16;
302     }
303 
304     @Override
305     public int getIntLE(int index) {
306         ensureAccessible();
307         return _getIntLE(index);
308     }
309 
310     @Override
311     public int getInt(int index) {
312         ensureAccessible();
313         return _getInt(index);
314     }
315 
316     @Override
317     protected int _getInt(int index) {
318         if (PlatformDependent.hasVarHandle()) {
319             return VarHandleByteBufferAccess.getIntBE(buffer, index);
320         }
321         return buffer.getInt(index);
322     }
323 
324     @Override
325     protected int _getIntLE(int index) {
326         if (PlatformDependent.hasVarHandle()) {
327             return VarHandleByteBufferAccess.getIntLE(buffer, index);
328         }
329         return ByteBufUtil.swapInt(buffer.getInt(index));
330     }
331 
332     @Override
333     public long getLongLE(int index) {
334         ensureAccessible();
335         return _getLongLE(index);
336     }
337 
338     @Override
339     public long getLong(int index) {
340         ensureAccessible();
341         return _getLong(index);
342     }
343 
344     @Override
345     protected long _getLong(int index) {
346         if (PlatformDependent.hasVarHandle()) {
347             return VarHandleByteBufferAccess.getLongBE(buffer, index);
348         }
349         return buffer.getLong(index);
350     }
351 
352     @Override
353     protected long _getLongLE(int index) {
354         if (PlatformDependent.hasVarHandle()) {
355             return VarHandleByteBufferAccess.getLongLE(buffer, index);
356         }
357         return ByteBufUtil.swapLong(buffer.getLong(index));
358     }
359 
360     @Override
361     public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
362         checkDstIndex(index, length, dstIndex, dst.capacity());
363         if (dst.hasArray()) {
364             getBytes(index, dst.array(), dst.arrayOffset() + dstIndex, length);
365         } else if (dst.nioBufferCount() > 0) {
366             for (ByteBuffer bb: dst.nioBuffers(dstIndex, length)) {
367                 int bbLen = bb.remaining();
368                 getBytes(index, bb);
369                 index += bbLen;
370             }
371         } else {
372             dst.setBytes(dstIndex, this, index, length);
373         }
374         return this;
375     }
376 
377     @Override
378     public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
379         getBytes(index, dst, dstIndex, length, false);
380         return this;
381     }
382 
383     void getBytes(int index, byte[] dst, int dstIndex, int length, boolean internal) {
384         checkDstIndex(index, length, dstIndex, dst.length);
385 
386         ByteBuffer tmpBuf;
387         if (internal) {
388             tmpBuf = internalNioBuffer(index, length);
389         } else {
390             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
391         }
392         tmpBuf.get(dst, dstIndex, length);
393     }
394 
395     @Override
396     public ByteBuf readBytes(byte[] dst, int dstIndex, int length) {
397         checkReadableBytes(length);
398         getBytes(readerIndex, dst, dstIndex, length, true);
399         readerIndex += length;
400         return this;
401     }
402 
403     @Override
404     public ByteBuf getBytes(int index, ByteBuffer dst) {
405         getBytes(index, dst, false);
406         return this;
407     }
408 
409     void getBytes(int index, ByteBuffer dst, boolean internal) {
410         checkIndex(index, dst.remaining());
411 
412         ByteBuffer tmpBuf;
413         if (internal) {
414             tmpBuf = internalNioBuffer(index, dst.remaining());
415         } else {
416             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + dst.remaining());
417         }
418         dst.put(tmpBuf);
419     }
420 
421     @Override
422     public ByteBuf readBytes(ByteBuffer dst) {
423         int length = dst.remaining();
424         checkReadableBytes(length);
425         getBytes(readerIndex, dst, true);
426         readerIndex += length;
427         return this;
428     }
429 
430     @Override
431     public ByteBuf setByte(int index, int value) {
432         ensureAccessible();
433         _setByte(index, value);
434         return this;
435     }
436 
437     @Override
438     protected void _setByte(int index, int value) {
439         buffer.put(index, (byte) (value & 0xFF));
440     }
441 
442     @Override
443     public ByteBuf setShortLE(int index, int value) {
444         ensureAccessible();
445         _setShortLE(index, value);
446         return this;
447     }
448 
449     @Override
450     public ByteBuf setShort(int index, int value) {
451         ensureAccessible();
452         _setShort(index, value);
453         return this;
454     }
455 
456     @Override
457     protected void _setShort(int index, int value) {
458         if (PlatformDependent.hasVarHandle()) {
459             VarHandleByteBufferAccess.setShortBE(buffer, index, value);
460             return;
461         }
462         buffer.putShort(index, (short) (value & 0xFFFF));
463     }
464 
465     @Override
466     protected void _setShortLE(int index, int value) {
467         if (PlatformDependent.hasVarHandle()) {
468             VarHandleByteBufferAccess.setShortLE(buffer, index, value);
469             return;
470         }
471         buffer.putShort(index, ByteBufUtil.swapShort((short) value));
472     }
473 
474     @Override
475     public ByteBuf setMediumLE(int index, int value) {
476         ensureAccessible();
477         _setMediumLE(index, value);
478         return this;
479     }
480 
481     @Override
482     public ByteBuf setMedium(int index, int value) {
483         ensureAccessible();
484         _setMedium(index, value);
485         return this;
486     }
487 
488     @Override
489     protected void _setMedium(int index, int value) {
490         setByte(index, (byte) (value >>> 16));
491         setByte(index + 1, (byte) (value >>> 8));
492         setByte(index + 2, (byte) value);
493     }
494 
495     @Override
496     protected void _setMediumLE(int index, int value) {
497         setByte(index, (byte) value);
498         setByte(index + 1, (byte) (value >>> 8));
499         setByte(index + 2, (byte) (value >>> 16));
500     }
501 
502     @Override
503     public ByteBuf setIntLE(int index, int value) {
504         ensureAccessible();
505         _setIntLE(index, value);
506         return this;
507     }
508 
509     @Override
510     public ByteBuf setInt(int index, int value) {
511         ensureAccessible();
512         _setInt(index, value);
513         return this;
514     }
515 
516     @Override
517     protected void _setInt(int index, int value) {
518         if (PlatformDependent.hasVarHandle()) {
519             VarHandleByteBufferAccess.setIntBE(buffer, index, value);
520             return;
521         }
522         buffer.putInt(index, value);
523     }
524 
525     @Override
526     protected void _setIntLE(int index, int value) {
527         if (PlatformDependent.hasVarHandle()) {
528             VarHandleByteBufferAccess.setIntLE(buffer, index, value);
529             return;
530         }
531         buffer.putInt(index, ByteBufUtil.swapInt(value));
532     }
533 
534     @Override
535     public ByteBuf setLong(int index, long value) {
536         ensureAccessible();
537         _setLong(index, value);
538         return this;
539     }
540 
541     @Override
542     public ByteBuf setLongLE(int index, long value) {
543         ensureAccessible();
544         _setLongLE(index, value);
545         return this;
546     }
547 
548     @Override
549     protected void _setLong(int index, long value) {
550         if (PlatformDependent.hasVarHandle()) {
551             VarHandleByteBufferAccess.setLongBE(buffer, index, value);
552             return;
553         }
554         buffer.putLong(index, value);
555     }
556 
557     @Override
558     protected void _setLongLE(int index, long value) {
559         if (PlatformDependent.hasVarHandle()) {
560             VarHandleByteBufferAccess.setLongLE(buffer, index, value);
561             return;
562         }
563         buffer.putLong(index, ByteBufUtil.swapLong(value));
564     }
565 
566     @Override
567     public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
568         checkSrcIndex(index, length, srcIndex, src.capacity());
569         if (src.nioBufferCount() > 0) {
570             for (ByteBuffer bb: src.nioBuffers(srcIndex, length)) {
571                 int bbLen = bb.remaining();
572                 setBytes(index, bb);
573                 index += bbLen;
574             }
575         } else {
576             src.getBytes(srcIndex, this, index, length);
577         }
578         return this;
579     }
580 
581     @Override
582     public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
583         checkSrcIndex(index, length, srcIndex, src.length);
584         ByteBuffer tmpBuf = internalNioBuffer(index, length);
585         tmpBuf.put(src, srcIndex, length);
586         return this;
587     }
588 
589     @Override
590     public ByteBuf setBytes(int index, ByteBuffer src) {
591         ensureAccessible();
592         if (src == tmpNioBuf) {
593             src = src.duplicate();
594         }
595         ByteBuffer tmpBuf = internalNioBuffer(index, src.remaining());
596         tmpBuf.put(src);
597         return this;
598     }
599 
600     @Override
601     public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException {
602         getBytes(index, out, length, false);
603         return this;
604     }
605 
606     void getBytes(int index, OutputStream out, int length, boolean internal) throws IOException {
607         ensureAccessible();
608         if (length == 0) {
609             return;
610         }
611         ByteBufUtil.readBytes(alloc(), internal ? _internalNioBuffer() : buffer.duplicate(), index, length, out);
612     }
613 
614     @Override
615     public ByteBuf readBytes(OutputStream out, int length) throws IOException {
616         checkReadableBytes(length);
617         getBytes(readerIndex, out, length, true);
618         readerIndex += length;
619         return this;
620     }
621 
622     @Override
623     public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
624         return getBytes(index, out, length, false);
625     }
626 
627     private int getBytes(int index, GatheringByteChannel out, int length, boolean internal) throws IOException {
628         ensureAccessible();
629         if (length == 0) {
630             return 0;
631         }
632 
633         ByteBuffer tmpBuf;
634         if (internal) {
635             tmpBuf = internalNioBuffer(index, length);
636         } else {
637             tmpBuf = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
638         }
639         return out.write(tmpBuf);
640     }
641 
642     @Override
643     public int getBytes(int index, FileChannel out, long position, int length) throws IOException {
644         return getBytes(index, out, position, length, false);
645     }
646 
647     private int getBytes(int index, FileChannel out, long position, int length, boolean internal) throws IOException {
648         ensureAccessible();
649         if (length == 0) {
650             return 0;
651         }
652 
653         ByteBuffer tmpBuf = internal ? internalNioBuffer(index, length) :
654                 (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
655         return out.write(tmpBuf, position);
656     }
657 
658     @Override
659     public int readBytes(GatheringByteChannel out, int length) throws IOException {
660         checkReadableBytes(length);
661         int readBytes = getBytes(readerIndex, out, length, true);
662         readerIndex += readBytes;
663         return readBytes;
664     }
665 
666     @Override
667     public int readBytes(FileChannel out, long position, int length) throws IOException {
668         checkReadableBytes(length);
669         int readBytes = getBytes(readerIndex, out, position, length, true);
670         readerIndex += readBytes;
671         return readBytes;
672     }
673 
674     @Override
675     public int setBytes(int index, InputStream in, int length) throws IOException {
676         ensureAccessible();
677         if (buffer.hasArray()) {
678             return in.read(buffer.array(), buffer.arrayOffset() + index, length);
679         } else {
680             byte[] tmp = ByteBufUtil.threadLocalTempArray(length);
681             int readBytes = in.read(tmp, 0, length);
682             if (readBytes <= 0) {
683                 return readBytes;
684             }
685             ByteBuffer tmpBuf = internalNioBuffer(index, readBytes);
686             tmpBuf.put(tmp, 0, readBytes);
687             return readBytes;
688         }
689     }
690 
691     @Override
692     public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
693         ensureAccessible();
694         ByteBuffer tmpBuf = internalNioBuffer(index, length);
695         try {
696             return in.read(tmpBuf);
697         } catch (ClosedChannelException ignored) {
698             return -1;
699         }
700     }
701 
702     @Override
703     public int setBytes(int index, FileChannel in, long position, int length) throws IOException {
704         ensureAccessible();
705         ByteBuffer tmpBuf = internalNioBuffer(index, length);
706         try {
707             return in.read(tmpBuf, position);
708         } catch (ClosedChannelException ignored) {
709             return -1;
710         }
711     }
712 
713     @Override
714     public int nioBufferCount() {
715         return 1;
716     }
717 
718     @Override
719     public ByteBuffer[] nioBuffers(int index, int length) {
720         return new ByteBuffer[] { nioBuffer(index, length) };
721     }
722 
723     @Override
724     public final boolean isContiguous() {
725         return true;
726     }
727 
728     @Override
729     public ByteBuf copy(int index, int length) {
730         ensureAccessible();
731         ByteBuffer src;
732         try {
733             src = (ByteBuffer) buffer.duplicate().clear().position(index).limit(index + length);
734         } catch (IllegalArgumentException ignored) {
735             throw new IndexOutOfBoundsException("Too many bytes to read - Need " + (index + length));
736         }
737 
738         return alloc().directBuffer(length, maxCapacity()).writeBytes(src);
739     }
740 
741     @Override
742     public ByteBuffer internalNioBuffer(int index, int length) {
743         checkIndex(index, length);
744         return (ByteBuffer) _internalNioBuffer().clear().position(index).limit(index + length);
745     }
746 
747     @Override
748     ByteBuffer _internalNioBuffer() {
749         ByteBuffer tmpNioBuf = this.tmpNioBuf;
750         if (tmpNioBuf == null) {
751             this.tmpNioBuf = tmpNioBuf = buffer.duplicate();
752         }
753         return tmpNioBuf;
754     }
755 
756     @Override
757     public ByteBuffer nioBuffer(int index, int length) {
758         checkIndex(index, length);
759         return PlatformDependent.offsetSlice(buffer, index, length);
760     }
761 
762     @Override
763     protected void deallocate() {
764         ByteBuffer buffer = this.buffer;
765         if (buffer == null) {
766             return;
767         }
768 
769         this.buffer = null;
770 
771         if (!doNotFree) {
772             if (cleanable != null) {
773                 cleanable.clean();
774                 cleanable = null;
775             } else {
776                 freeDirect(buffer);
777             }
778         }
779     }
780 
781     @Override
782     public ByteBuf unwrap() {
783         return null;
784     }
785 }