DirectByteBuffer.java revision 9b30f636b4ce3e4c48a817d7b2f7bd7a8d579631
1/*
2 * Copyright (c) 2000, 2011, 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 java.nio;
27
28import java.io.FileDescriptor;
29import sun.misc.Cleaner;
30import sun.misc.Unsafe;
31import sun.misc.VM;
32import sun.nio.ch.DirectBuffer;
33import libcore.io.SizeOf;
34import libcore.io.Memory;
35import dalvik.system.VMRuntime;
36
37class DirectByteBuffer extends MappedByteBuffer
38    implements DirectBuffer {
39
40    //there is no use of it in the class. Remove it after making
41    //changes in the child classes.
42    protected static final Unsafe unsafe = Bits.unsafe();
43
44    // Cached unaligned-access capability
45    private static Boolean unalignedCache;
46    protected static boolean unaligned() {
47        if (unalignedCache == null) {
48            unalignedCache = Bits.unaligned();
49        }
50        return unalignedCache;
51    }
52
53    // Base address, used in all indexing calculations
54    // NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress
55    //    protected long address;
56
57    // An object attached to this buffer. If this buffer is a view of another
58    // buffer then we use this field to keep a reference to that buffer to
59    // ensure that its memory isn't freed before we are done with it.
60    private final Object att;
61
62    private boolean accessible = true;
63    private boolean freed = false;
64
65
66    public Object attachment() {
67        return att;
68    }
69
70    private class Deallocator implements Runnable {
71
72        public void run() {
73            free();
74        }
75    }
76
77    private Cleaner cleaner;
78
79    public Cleaner cleaner() { return cleaner; }
80
81    DirectByteBuffer(int capacity) {
82        super(-1, 0, capacity, capacity, (byte[]) VMRuntime.getRuntime()
83              .newNonMovableArray(byte.class, capacity), 0);
84        VMRuntime runtime = VMRuntime.getRuntime();
85        address = runtime.addressOf(hb);
86        cleaner = Cleaner.create(this, new Deallocator());
87        this.isReadOnly = false;
88        att = null;
89    }
90
91    DirectByteBuffer(long addr, int cap, Object ob) {
92        super(-1, 0, cap, cap);
93        address = addr;
94        cleaner = null;
95        att = ob;
96    }
97
98    // Invoked only by JNI: NewDirectByteBuffer(void*, long)
99    //
100    private DirectByteBuffer(long addr, int cap) {
101        super(-1, 0, cap, cap);
102        address = addr;
103        cleaner = null;
104        att = null;
105    }
106
107    // For memory-mapped buffers -- invoked by FileChannelImpl via reflection
108    //
109    protected DirectByteBuffer(int cap, long addr,
110                               FileDescriptor fd,
111                               Runnable unmapper) {
112        this(cap, addr, fd, unmapper, false);
113    }
114
115    protected DirectByteBuffer(int cap, long addr,
116                               FileDescriptor fd,
117                               Runnable unmapper,
118                               boolean isReadOnly) {
119        super(-1, 0, cap, cap, fd);
120        this.isReadOnly = isReadOnly;
121        address = addr;
122        cleaner = Cleaner.create(this, unmapper);
123        att = null;
124    }
125
126    // For duplicates and slices
127    //
128    DirectByteBuffer(DirectBuffer db,         // package-private
129                     int mark, int pos, int lim, int cap,
130                     int off) {
131        this(db, mark, pos, lim, cap, off, false);
132    }
133
134    DirectByteBuffer(DirectBuffer db,         // package-private
135                     int mark, int pos, int lim, int cap,
136                     int off, boolean isReadOnly) {
137        super(mark, pos, lim, cap);
138        this.isReadOnly = isReadOnly;
139        address = db.address() + off;
140        cleaner = null;
141        att = db;
142    }
143
144    public ByteBuffer slice() {
145        int pos = this.position();
146        int lim = this.limit();
147        assert (pos <= lim);
148        int rem = (pos <= lim ? lim - pos : 0);
149        int off = (pos << 0);
150        assert (off >= 0);
151        return new DirectByteBuffer(this, -1, 0, rem, rem, off, isReadOnly);
152    }
153
154    public ByteBuffer duplicate() {
155        return new DirectByteBuffer(this,
156                                    this.markValue(),
157                                    this.position(),
158                                    this.limit(),
159                                    this.capacity(),
160                                    0,
161                                    isReadOnly);
162    }
163
164    public ByteBuffer asReadOnlyBuffer() {
165
166        return new DirectByteBuffer(this,
167                                    this.markValue(),
168                                    this.position(),
169                                    this.limit(),
170                                    this.capacity(),
171                                    0,
172                                    true);
173    }
174
175    public long address() {
176        return address;
177    }
178
179    private long ix(int i) {
180        return address + (i << 0);
181    }
182
183    public byte get(long a) {
184        return Memory.peekByte(a);
185    }
186
187    public byte get() {
188        if (freed) {
189            throw new IllegalStateException("buffer was freed");
190        }
191        return get(address + nextGetIndex());
192    }
193
194    public byte get(int i) {
195        if (freed) {
196            throw new IllegalStateException("buffer was freed");
197        }
198        return get(address + checkIndex(i));
199    }
200
201    public ByteBuffer get(byte[] dst, int dstOffset, int length) {
202        if (freed) {
203            throw new IllegalStateException("buffer was freed");
204        }
205        checkBounds(dstOffset, length, dst.length);
206        int pos = position();
207        int lim = limit();
208        assert (pos <= lim);
209        int rem = (pos <= lim ? lim - pos : 0);
210        if (length > rem)
211            throw new BufferUnderflowException();
212        Memory.peekByteArray((int) address + pos,
213                             dst, dstOffset, length);
214        position = pos + length;
215        return this;
216    }
217
218    public ByteBuffer put(long a, byte x) {
219        Memory.pokeByte(a, x);
220        return this;
221    }
222
223    public ByteBuffer put(byte x) {
224        if (isReadOnly) {
225            throw new ReadOnlyBufferException();
226        }
227        if (freed) {
228            throw new IllegalStateException("buffer was freed");
229        }
230        put(ix(nextPutIndex()), x);
231        return this;
232    }
233
234    public ByteBuffer put(int i, byte x) {
235        if (isReadOnly) {
236            throw new ReadOnlyBufferException();
237        }
238        if (freed) {
239            throw new IllegalStateException("buffer was freed");
240        }
241        put(ix(checkIndex(i)), x);
242        return this;
243    }
244
245    public ByteBuffer put(ByteBuffer src) {
246        if (isReadOnly) {
247            throw new ReadOnlyBufferException();
248        }
249        if (freed) {
250            throw new IllegalStateException("buffer was freed");
251        }
252        if (src instanceof DirectByteBuffer) {
253            if (src == this)
254                throw new IllegalArgumentException();
255            DirectByteBuffer sb = (DirectByteBuffer)src;
256            byte[] arr = sb.array();
257            put(arr, src.offset, arr.length);
258        } else if (src.hb != null) {
259            int spos = src.position();
260            int slim = src.limit();
261            assert (spos <= slim);
262            int srem = (spos <= slim ? slim - spos : 0);
263            put(src.hb, src.offset + spos, srem);
264            src.position(spos + srem);
265        } else {
266            super.put(src);
267        }
268        return this;
269    }
270
271    public ByteBuffer put(byte[] src, int srcOffset, int length) {
272        if (isReadOnly) {
273            throw new ReadOnlyBufferException();
274        }
275        if (freed) {
276            throw new IllegalStateException("buffer was freed");
277        }
278        checkBounds(srcOffset, length, src.length);
279        int pos = position();
280        int lim = limit();
281        assert (pos <= lim);
282        int rem = (pos <= lim ? lim - pos : 0);
283        if (length > rem)
284            throw new BufferOverflowException();
285        Memory.pokeByteArray((int) address + pos,
286                             src, srcOffset, length);
287        position = pos + length;
288        return this;
289    }
290
291    public ByteBuffer compact() {
292        if (isReadOnly) {
293            throw new ReadOnlyBufferException();
294        }
295        if (freed) {
296            throw new IllegalStateException("buffer was freed");
297        }
298        int pos = position();
299        int lim = limit();
300        assert (pos <= lim);
301        int rem = (pos <= lim ? lim - pos : 0);
302        Memory.memmove(this, 0, this, position, remaining());
303        position(rem);
304        limit(capacity());
305        discardMark();
306        return this;
307    }
308
309    public boolean isDirect() {
310        return true;
311    }
312
313    public boolean isReadOnly() {
314        return isReadOnly;
315    }
316
317    byte _get(int i) {                          // package-private
318        return get(i);
319    }
320
321    void _put(int i, byte b) {                  // package-private
322        put(i, b);
323    }
324
325    private char getChar(long a) {
326        if (freed) {
327            throw new IllegalStateException("buffer was freed");
328        }
329        return (char) Memory.peekShort(position, !nativeByteOrder);
330    }
331
332    public char getChar() {
333        if (freed) {
334            throw new IllegalStateException("buffer was freed");
335        }
336        int newPosition = position + SizeOf.CHAR;
337        if (newPosition > limit()) {
338            throw new BufferUnderflowException();
339        }
340        char x = (char) Memory.peekShort(address + position, !nativeByteOrder);
341        position = newPosition;
342        return x;
343    }
344
345    public char getChar(int i) {
346        if (freed) {
347            throw new IllegalStateException("buffer was freed");
348        }
349        checkIndex(i, SizeOf.CHAR);
350        char x = (char)Memory.peekShort(address + i, !nativeByteOrder);
351        return x;
352    }
353
354    private ByteBuffer putChar(long a, char x) {
355        Memory.pokeShort(a, (short) x, !nativeByteOrder);
356        return this;
357    }
358
359    public ByteBuffer putChar(char x) {
360        if (isReadOnly) {
361            throw new ReadOnlyBufferException();
362        }
363        if (freed) {
364            throw new IllegalStateException("buffer was freed");
365        }
366        putChar(ix(nextPutIndex(SizeOf.CHAR)), x);
367        return this;
368    }
369
370    public ByteBuffer putChar(int i, char x) {
371        if (isReadOnly) {
372            throw new ReadOnlyBufferException();
373        }
374        if (freed) {
375            throw new IllegalStateException("buffer was freed");
376        }
377        putChar(ix(checkIndex(i, SizeOf.CHAR)), x);
378        return this;
379    }
380
381    public CharBuffer asCharBuffer() {
382        int off = this.position();
383        int lim = this.limit();
384        assert (off <= lim);
385        int rem = (off <= lim ? lim - off : 0);
386
387        int size = rem >> 1;
388        if (!unaligned() && ((address + off) % SizeOf.CHAR != 0)) {
389            return  (CharBuffer)(new ByteBufferAsCharBuffer(this,
390                                                            -1,
391                                                            0,
392                                                            size,
393                                                            size,
394                                                            off,
395                                                            order(),
396                                                            isReadOnly));
397        } else {
398            return (nativeByteOrder
399                    ? (CharBuffer)(new DirectCharBufferU(this,
400                                                         -1,
401                                                         0,
402                                                         size,
403                                                         size,
404                                                         off))
405                    : (CharBuffer)(new DirectCharBufferS(this,
406                                                         -1,
407                                                         0,
408                                                         size,
409                                                         size,
410                                                         off)));
411        }
412    }
413
414    private short getShort(long a) {
415        return Memory.peekShort(a, !nativeByteOrder);
416    }
417
418    public short getShort() {
419        if (freed) {
420            throw new IllegalStateException("buffer was freed");
421        }
422        return getShort(ix(nextGetIndex(SizeOf.SHORT)));
423    }
424
425    public short getShort(int i) {
426        if (freed) {
427            throw new IllegalStateException("buffer was freed");
428        }
429        return getShort(ix(checkIndex(i, SizeOf.SHORT)));
430    }
431
432    private ByteBuffer putShort(long a, short x) {
433        Memory.pokeShort(a, x, !nativeByteOrder);
434        return this;
435    }
436
437    public ByteBuffer putShort(short x) {
438        if (isReadOnly) {
439            throw new ReadOnlyBufferException();
440        }
441        if (freed) {
442            throw new IllegalStateException("buffer was freed");
443        }
444        putShort(ix(nextPutIndex(SizeOf.SHORT)), x);
445        return this;
446    }
447
448    public ByteBuffer putShort(int i, short x) {
449        if (isReadOnly) {
450            throw new ReadOnlyBufferException();
451        }
452        if (freed) {
453            throw new IllegalStateException("buffer was freed");
454        }
455        putShort(ix(checkIndex(i, SizeOf.SHORT)), x);
456        return this;
457    }
458
459    public ShortBuffer asShortBuffer() {
460        int off = this.position();
461        int lim = this.limit();
462        assert (off <= lim);
463        int rem = (off <= lim ? lim - off : 0);
464
465        int size = rem >> 1;
466        if (!unaligned() && ((address + off) % SizeOf.SHORT != 0)) {
467            return (ShortBuffer)(new ByteBufferAsShortBuffer(this,
468                                                             -1,
469                                                             0,
470                                                             size,
471                                                             size,
472                                                             off,
473                                                             order(),
474                                                             isReadOnly));
475        } else {
476            return (nativeByteOrder
477                    ? (ShortBuffer)(new DirectShortBufferU(this,
478                                                           -1,
479                                                           0,
480                                                           size,
481                                                           size,
482                                                           off))
483                    : (ShortBuffer)(new DirectShortBufferS(this,
484                                                           -1,
485                                                           0,
486                                                           size,
487                                                           size,
488                                                           off)));
489        }
490    }
491
492    private int getInt(long a) {
493        return  Memory.peekInt(a, !nativeByteOrder);
494    }
495
496    public int getInt() {
497        if (freed) {
498            throw new IllegalStateException("buffer was freed");
499        }
500        return getInt(ix(nextGetIndex(SizeOf.INT)));
501    }
502
503    public int getInt(int i) {
504        if (freed) {
505            throw new IllegalStateException("buffer was freed");
506        }
507        return getInt(ix(checkIndex(i, (SizeOf.INT))));
508    }
509
510    private ByteBuffer putInt(long a, int x) {
511        Memory.pokeInt(a, x, !nativeByteOrder);
512        return this;
513    }
514
515    public ByteBuffer putInt(int x) {
516        if (isReadOnly) {
517            throw new ReadOnlyBufferException();
518        }
519        if (freed) {
520            throw new IllegalStateException("buffer was freed");
521        }
522        putInt(ix(nextPutIndex(SizeOf.INT)), x);
523        return this;
524    }
525
526    public ByteBuffer putInt(int i, int x) {
527        if (isReadOnly) {
528            throw new ReadOnlyBufferException();
529        }
530        if (freed) {
531            throw new IllegalStateException("buffer was freed");
532        }
533        putInt(ix(checkIndex(i, SizeOf.INT)), x);
534        return this;
535    }
536
537    public IntBuffer asIntBuffer() {
538        int off = this.position();
539        int lim = this.limit();
540        assert (off <= lim);
541        int rem = (off <= lim ? lim - off : 0);
542        int size = rem >> 2;
543        if (!unaligned() && ((address + off) % SizeOf.INT != 0)) {
544            return (IntBuffer)(new ByteBufferAsIntBuffer(this,
545                                                         -1,
546                                                         0,
547                                                         size,
548                                                         size,
549                                                         off,
550                                                         order(),
551                                                         isReadOnly));
552        } else {
553            return (nativeByteOrder
554                    ? (IntBuffer)(new DirectIntBufferU(this,
555                                                       -1,
556                                                       0,
557                                                       size,
558                                                       size,
559                                                       off))
560                    : (IntBuffer)(new DirectIntBufferS(this,
561                                                       -1,
562                                                       0,
563                                                       size,
564                                                       size,
565                                                       off)));
566        }
567    }
568
569    private long getLong(long a) {
570        return Memory.peekLong(a, !nativeByteOrder);
571    }
572
573    public long getLong() {
574        if (freed) {
575            throw new IllegalStateException("buffer was freed");
576        }
577        return getLong(ix(nextGetIndex(SizeOf.LONG)));
578    }
579
580    public long getLong(int i) {
581        if (freed) {
582            throw new IllegalStateException("buffer was freed");
583        }
584        return getLong(ix(checkIndex(i, SizeOf.LONG)));
585    }
586
587    private ByteBuffer putLong(long a, long x) {
588        Memory.pokeLong(a, x, !nativeByteOrder);
589        return this;
590    }
591
592    public ByteBuffer putLong(long x) {
593        if (isReadOnly) {
594            throw new ReadOnlyBufferException();
595        }
596        if (freed) {
597            throw new IllegalStateException("buffer was freed");
598        }
599        putLong(ix(nextPutIndex(SizeOf.LONG)), x);
600        return this;
601    }
602
603    public ByteBuffer putLong(int i, long x) {
604        if (isReadOnly) {
605            throw new ReadOnlyBufferException();
606        }
607        if (freed) {
608            throw new IllegalStateException("buffer was freed");
609        }
610        putLong(ix(checkIndex(i, SizeOf.LONG)), x);
611        return this;
612    }
613
614    public LongBuffer asLongBuffer() {
615        int off = this.position();
616        int lim = this.limit();
617        assert (off <= lim);
618        int rem = (off <= lim ? lim - off : 0);
619        int size = rem >> 3;
620        if (!unaligned() && ((address + off) % SizeOf.LONG != 0)) {
621            return (LongBuffer)(new ByteBufferAsLongBuffer(this,
622                                                           -1,
623                                                           0,
624                                                           size,
625                                                           size,
626                                                           off,
627                                                           order(),
628                                                           isReadOnly));
629        } else {
630            return (nativeByteOrder
631                    ? (LongBuffer)(new DirectLongBufferU(this,
632                                                         -1,
633                                                         0,
634                                                         size,
635                                                         size,
636                                                         off))
637                    : (LongBuffer)(new DirectLongBufferS(this,
638                                                         -1,
639                                                         0,
640                                                         size,
641                                                         size,
642                                                         off)));
643        }
644    }
645
646    private float getFloat(long a) {
647        int x = Memory.peekInt(a, !nativeByteOrder);
648        return Float.intBitsToFloat(x);
649    }
650
651    public float getFloat() {
652        if (freed) {
653            throw new IllegalStateException("buffer was freed");
654        }
655        return getFloat(ix(nextGetIndex(SizeOf.FLOAT)));
656    }
657
658    public float getFloat(int i) {
659        if (freed) {
660            throw new IllegalStateException("buffer was freed");
661        }
662        return getFloat(ix(checkIndex(i, SizeOf.FLOAT)));
663    }
664
665    private ByteBuffer putFloat(long a, float x) {
666        int y = Float.floatToRawIntBits(x);
667        Memory.pokeInt(a, y, !nativeByteOrder);
668        return this;
669    }
670
671    public ByteBuffer putFloat(float x) {
672        if (isReadOnly) {
673            throw new ReadOnlyBufferException();
674        }
675        if (freed) {
676            throw new IllegalStateException("buffer was freed");
677        }
678        putFloat(ix(nextPutIndex(SizeOf.FLOAT)), x);
679        return this;
680    }
681
682    public ByteBuffer putFloat(int i, float x) {
683        if (isReadOnly) {
684            throw new ReadOnlyBufferException();
685        }
686        if (freed) {
687            throw new IllegalStateException("buffer was freed");
688        }
689        putFloat(ix(checkIndex(i, SizeOf.FLOAT)), x);
690        return this;
691    }
692
693    public FloatBuffer asFloatBuffer() {
694        int off = this.position();
695        int lim = this.limit();
696        assert (off <= lim);
697        int rem = (off <= lim ? lim - off : 0);
698        int size = rem >> 2;
699        if (!unaligned() && ((address + off) % SizeOf.FLOAT != 0)) {
700            return (FloatBuffer)(new ByteBufferAsFloatBuffer(this,
701                                                             -1,
702                                                             0,
703                                                             size,
704                                                             size,
705                                                             off,
706                                                             order(),
707                                                             isReadOnly));
708        } else {
709            return (nativeByteOrder
710                    ? (FloatBuffer)(new DirectFloatBufferU(this,
711                                                           -1,
712                                                           0,
713                                                           size,
714                                                           size,
715                                                           off))
716                    : (FloatBuffer)(new DirectFloatBufferS(this,
717                                                           -1,
718                                                           0,
719                                                           size,
720                                                           size,
721                                                           off)));
722        }
723    }
724
725    private double getDouble(long a) {
726        long x = Memory.peekLong(a, !nativeByteOrder);
727        return Double.longBitsToDouble(x);
728    }
729
730    public double getDouble() {
731        if (freed) {
732            throw new IllegalStateException("buffer was freed");
733        }
734        return getDouble(ix(nextGetIndex(SizeOf.DOUBLE)));
735    }
736
737    public double getDouble(int i) {
738        if (freed) {
739            throw new IllegalStateException("buffer was freed");
740        }
741        return getDouble(ix(checkIndex(i, SizeOf.DOUBLE)));
742    }
743
744    private ByteBuffer putDouble(long a, double x) {
745        long y = Double.doubleToRawLongBits(x);
746        Memory.pokeLong(a, y, !nativeByteOrder);
747        return this;
748    }
749
750    public ByteBuffer putDouble(double x) {
751        if (isReadOnly) {
752            throw new ReadOnlyBufferException();
753        }
754        if (freed) {
755            throw new IllegalStateException("buffer was freed");
756        }
757        putDouble(ix(nextPutIndex(SizeOf.DOUBLE)), x);
758        return this;
759    }
760
761    public ByteBuffer putDouble(int i, double x) {
762        if (isReadOnly) {
763            throw new ReadOnlyBufferException();
764        }
765        if (freed) {
766            throw new IllegalStateException("buffer was freed");
767        }
768        putDouble(ix(checkIndex(i, SizeOf.DOUBLE)), x);
769        return this;
770    }
771
772    public DoubleBuffer asDoubleBuffer() {
773        int off = this.position();
774        int lim = this.limit();
775        assert (off <= lim);
776        int rem = (off <= lim ? lim - off : 0);
777
778        int size = rem >> 3;
779        if (!unaligned() && ((address + off) % SizeOf.DOUBLE != 0)) {
780            return (DoubleBuffer)(new ByteBufferAsDoubleBuffer(this,
781                                                               -1,
782                                                               0,
783                                                               size,
784                                                               size,
785                                                               off,
786                                                               order(),
787                                                               isReadOnly));
788        } else {
789            return (nativeByteOrder
790                    ? (DoubleBuffer)(new DirectDoubleBufferU(this,
791                                                             -1,
792                                                             0,
793                                                             size,
794                                                             size,
795                                                             off))
796                    : (DoubleBuffer)(new DirectDoubleBufferS(this,
797                                                             -1,
798                                                             0,
799                                                             size,
800                                                             size,
801                                                             off)));
802        }
803    }
804
805    public final void free() {
806        freed = true;
807    }
808
809    private final void checkIfFreed() {
810        if (freed) {
811            throw new IllegalStateException("buffer was freed");
812        }
813    }
814}
815