1/*
2 * Copyright (c) 2000, 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
26#warn This file is preprocessed before being compiled
27
28package java.nio;
29
30import java.io.FileDescriptor;
31import jdk.internal.misc.Unsafe;
32import jdk.internal.misc.VM;
33import jdk.internal.ref.Cleaner;
34import sun.nio.ch.DirectBuffer;
35
36
37class Direct$Type$Buffer$RW$$BO$
38#if[rw]
39    extends {#if[byte]?Mapped$Type$Buffer:$Type$Buffer}
40#else[rw]
41    extends Direct$Type$Buffer$BO$
42#end[rw]
43    implements DirectBuffer
44{
45
46#if[rw]
47
48    // Cached unsafe-access object
49    protected static final Unsafe unsafe = Bits.unsafe();
50
51    // Cached array base offset
52    private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset($type$[].class);
53
54    // Cached unaligned-access capability
55    protected static final boolean unaligned = Bits.unaligned();
56
57    // Base address, used in all indexing calculations
58    // NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress
59    //    protected long address;
60
61    // An object attached to this buffer. If this buffer is a view of another
62    // buffer then we use this field to keep a reference to that buffer to
63    // ensure that its memory isn't freed before we are done with it.
64    private final Object att;
65
66    public Object attachment() {
67        return att;
68    }
69
70#if[byte]
71
72    private static class Deallocator
73        implements Runnable
74    {
75
76        private static Unsafe unsafe = Unsafe.getUnsafe();
77
78        private long address;
79        private long size;
80        private int capacity;
81
82        private Deallocator(long address, long size, int capacity) {
83            assert (address != 0);
84            this.address = address;
85            this.size = size;
86            this.capacity = capacity;
87        }
88
89        public void run() {
90            if (address == 0) {
91                // Paranoia
92                return;
93            }
94            unsafe.freeMemory(address);
95            address = 0;
96            Bits.unreserveMemory(size, capacity);
97        }
98
99    }
100
101    private final Cleaner cleaner;
102
103    public Cleaner cleaner() { return cleaner; }
104
105#else[byte]
106
107    public Cleaner cleaner() { return null; }
108
109#end[byte]
110
111#end[rw]
112
113#if[byte]
114
115    // Primary constructor
116    //
117    Direct$Type$Buffer$RW$(int cap) {                   // package-private
118#if[rw]
119        super(-1, 0, cap, cap);
120        boolean pa = VM.isDirectMemoryPageAligned();
121        int ps = Bits.pageSize();
122        long size = Math.max(1L, (long)cap + (pa ? ps : 0));
123        Bits.reserveMemory(size, cap);
124
125        long base = 0;
126        try {
127            base = unsafe.allocateMemory(size);
128        } catch (OutOfMemoryError x) {
129            Bits.unreserveMemory(size, cap);
130            throw x;
131        }
132        unsafe.setMemory(base, size, (byte) 0);
133        if (pa && (base % ps != 0)) {
134            // Round up to page boundary
135            address = base + ps - (base & (ps - 1));
136        } else {
137            address = base;
138        }
139        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
140        att = null;
141#else[rw]
142        super(cap);
143        this.isReadOnly = true;
144#end[rw]
145    }
146
147#if[rw]
148
149    // Invoked to construct a direct ByteBuffer referring to the block of
150    // memory. A given arbitrary object may also be attached to the buffer.
151    //
152    Direct$Type$Buffer(long addr, int cap, Object ob) {
153        super(-1, 0, cap, cap);
154        address = addr;
155        cleaner = null;
156        att = ob;
157    }
158
159
160    // Invoked only by JNI: NewDirectByteBuffer(void*, long)
161    //
162    private Direct$Type$Buffer(long addr, int cap) {
163        super(-1, 0, cap, cap);
164        address = addr;
165        cleaner = null;
166        att = null;
167    }
168
169#end[rw]
170
171    // For memory-mapped buffers -- invoked by FileChannelImpl via reflection
172    //
173    protected Direct$Type$Buffer$RW$(int cap, long addr,
174                                     FileDescriptor fd,
175                                     Runnable unmapper)
176    {
177#if[rw]
178        super(-1, 0, cap, cap, fd);
179        address = addr;
180        cleaner = Cleaner.create(this, unmapper);
181        att = null;
182#else[rw]
183        super(cap, addr, fd, unmapper);
184        this.isReadOnly = true;
185#end[rw]
186    }
187
188#end[byte]
189
190    // For duplicates and slices
191    //
192    Direct$Type$Buffer$RW$$BO$(DirectBuffer db,         // package-private
193                               int mark, int pos, int lim, int cap,
194                               int off)
195    {
196#if[rw]
197        super(mark, pos, lim, cap);
198        address = db.address() + off;
199#if[byte]
200        cleaner = null;
201#end[byte]
202        att = db;
203#else[rw]
204        super(db, mark, pos, lim, cap, off);
205        this.isReadOnly = true;
206#end[rw]
207    }
208
209    public $Type$Buffer slice() {
210        int pos = this.position();
211        int lim = this.limit();
212        assert (pos <= lim);
213        int rem = (pos <= lim ? lim - pos : 0);
214        int off = (pos << $LG_BYTES_PER_VALUE$);
215        assert (off >= 0);
216        return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off);
217    }
218
219#if[byte]
220    public $Type$Buffer slice(int pos, int lim) {
221        assert (pos >= 0);
222        assert (pos <= lim);
223        int rem = lim - pos;
224        return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, pos);
225    }
226#end[byte]
227
228    public $Type$Buffer duplicate() {
229        return new Direct$Type$Buffer$RW$$BO$(this,
230                                              this.markValue(),
231                                              this.position(),
232                                              this.limit(),
233                                              this.capacity(),
234                                              0);
235    }
236
237    public $Type$Buffer asReadOnlyBuffer() {
238#if[rw]
239        return new Direct$Type$BufferR$BO$(this,
240                                           this.markValue(),
241                                           this.position(),
242                                           this.limit(),
243                                           this.capacity(),
244                                           0);
245#else[rw]
246        return duplicate();
247#end[rw]
248    }
249
250#if[rw]
251
252    public long address() {
253        return address;
254    }
255
256    private long ix(int i) {
257        return address + ((long)i << $LG_BYTES_PER_VALUE$);
258    }
259
260    public $type$ get() {
261        return $fromBits$($swap$(unsafe.get$Swaptype$(ix(nextGetIndex()))));
262    }
263
264    public $type$ get(int i) {
265        return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i)))));
266    }
267
268#if[streamableType]
269    $type$ getUnchecked(int i) {
270        return $fromBits$($swap$(unsafe.get$Swaptype$(ix(i))));
271    }
272#end[streamableType]
273
274    public $Type$Buffer get($type$[] dst, int offset, int length) {
275#if[rw]
276        if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
277            checkBounds(offset, length, dst.length);
278            int pos = position();
279            int lim = limit();
280            assert (pos <= lim);
281            int rem = (pos <= lim ? lim - pos : 0);
282            if (length > rem)
283                throw new BufferUnderflowException();
284
285            long dstOffset = arrayBaseOffset + ((long)offset << $LG_BYTES_PER_VALUE$);
286#if[!byte]
287            if (order() != ByteOrder.nativeOrder())
288                unsafe.copySwapMemory(null,
289                                      ix(pos),
290                                      dst,
291                                      dstOffset,
292                                      (long)length << $LG_BYTES_PER_VALUE$,
293                                      (long)1 << $LG_BYTES_PER_VALUE$);
294            else
295#end[!byte]
296                unsafe.copyMemory(null,
297                                  ix(pos),
298                                  dst,
299                                  dstOffset,
300                                  (long)length << $LG_BYTES_PER_VALUE$);
301            position(pos + length);
302        } else {
303            super.get(dst, offset, length);
304        }
305        return this;
306#else[rw]
307        throw new ReadOnlyBufferException();
308#end[rw]
309    }
310
311#end[rw]
312
313    public $Type$Buffer put($type$ x) {
314#if[rw]
315        unsafe.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
316        return this;
317#else[rw]
318        throw new ReadOnlyBufferException();
319#end[rw]
320    }
321
322    public $Type$Buffer put(int i, $type$ x) {
323#if[rw]
324        unsafe.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
325        return this;
326#else[rw]
327        throw new ReadOnlyBufferException();
328#end[rw]
329    }
330
331    public $Type$Buffer put($Type$Buffer src) {
332#if[rw]
333        if (src instanceof Direct$Type$Buffer$BO$) {
334            if (src == this)
335                throw createSameBufferException();
336            Direct$Type$Buffer$RW$$BO$ sb = (Direct$Type$Buffer$RW$$BO$)src;
337
338            int spos = sb.position();
339            int slim = sb.limit();
340            assert (spos <= slim);
341            int srem = (spos <= slim ? slim - spos : 0);
342
343            int pos = position();
344            int lim = limit();
345            assert (pos <= lim);
346            int rem = (pos <= lim ? lim - pos : 0);
347
348            if (srem > rem)
349                throw new BufferOverflowException();
350            unsafe.copyMemory(sb.ix(spos), ix(pos), (long)srem << $LG_BYTES_PER_VALUE$);
351            sb.position(spos + srem);
352            position(pos + srem);
353        } else if (src.hb != null) {
354
355            int spos = src.position();
356            int slim = src.limit();
357            assert (spos <= slim);
358            int srem = (spos <= slim ? slim - spos : 0);
359
360            put(src.hb, src.offset + spos, srem);
361            src.position(spos + srem);
362
363        } else {
364            super.put(src);
365        }
366        return this;
367#else[rw]
368        throw new ReadOnlyBufferException();
369#end[rw]
370    }
371
372    public $Type$Buffer put($type$[] src, int offset, int length) {
373#if[rw]
374        if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
375            checkBounds(offset, length, src.length);
376            int pos = position();
377            int lim = limit();
378            assert (pos <= lim);
379            int rem = (pos <= lim ? lim - pos : 0);
380            if (length > rem)
381                throw new BufferOverflowException();
382
383            long srcOffset = arrayBaseOffset + ((long)offset << $LG_BYTES_PER_VALUE$);
384#if[!byte]
385            if (order() != ByteOrder.nativeOrder())
386                unsafe.copySwapMemory(src,
387                                      srcOffset,
388                                      null,
389                                      ix(pos),
390                                      (long)length << $LG_BYTES_PER_VALUE$,
391                                      (long)1 << $LG_BYTES_PER_VALUE$);
392            else
393#end[!byte]
394                unsafe.copyMemory(src,
395                                  srcOffset,
396                                  null,
397                                  ix(pos),
398                                  (long)length << $LG_BYTES_PER_VALUE$);
399            position(pos + length);
400        } else {
401            super.put(src, offset, length);
402        }
403        return this;
404#else[rw]
405        throw new ReadOnlyBufferException();
406#end[rw]
407    }
408
409    public $Type$Buffer compact() {
410#if[rw]
411        int pos = position();
412        int lim = limit();
413        assert (pos <= lim);
414        int rem = (pos <= lim ? lim - pos : 0);
415
416        unsafe.copyMemory(ix(pos), ix(0), (long)rem << $LG_BYTES_PER_VALUE$);
417        position(rem);
418        limit(capacity());
419        discardMark();
420        return this;
421#else[rw]
422        throw new ReadOnlyBufferException();
423#end[rw]
424    }
425
426    public boolean isDirect() {
427        return true;
428    }
429
430    public boolean isReadOnly() {
431        return {#if[rw]?false:true};
432    }
433
434
435#if[char]
436
437    public String toString(int start, int end) {
438        if ((end > limit()) || (start > end))
439            throw new IndexOutOfBoundsException();
440        try {
441            int len = end - start;
442            char[] ca = new char[len];
443            CharBuffer cb = CharBuffer.wrap(ca);
444            CharBuffer db = this.duplicate();
445            db.position(start);
446            db.limit(end);
447            cb.put(db);
448            return new String(ca);
449        } catch (StringIndexOutOfBoundsException x) {
450            throw new IndexOutOfBoundsException();
451        }
452    }
453
454
455    // --- Methods to support CharSequence ---
456
457    public CharBuffer subSequence(int start, int end) {
458        int pos = position();
459        int lim = limit();
460        assert (pos <= lim);
461        pos = (pos <= lim ? pos : lim);
462        int len = lim - pos;
463
464        if ((start < 0) || (end > len) || (start > end))
465            throw new IndexOutOfBoundsException();
466        return new DirectCharBuffer$RW$$BO$(this,
467                                            -1,
468                                            pos + start,
469                                            pos + end,
470                                            capacity(),
471                                            offset);
472    }
473
474#end[char]
475
476
477
478#if[!byte]
479
480    public ByteOrder order() {
481#if[boS]
482        return ((ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
483                ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
484#end[boS]
485#if[boU]
486        return ((ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN)
487                ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
488#end[boU]
489    }
490
491#end[!byte]
492
493
494
495#if[byte]
496
497    byte _get(int i) {                          // package-private
498        return unsafe.getByte(address + i);
499    }
500
501    void _put(int i, byte b) {                  // package-private
502#if[rw]
503        unsafe.putByte(address + i, b);
504#else[rw]
505        throw new ReadOnlyBufferException();
506#end[rw]
507    }
508
509    // #BIN
510    //
511    // Binary-data access methods  for short, char, int, long, float,
512    // and double will be inserted here
513
514#end[byte]
515
516}
517