1/*
2 * Copyright (c) 2000, 2021, 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 java.lang.ref.Reference;
32import java.util.Objects;
33import jdk.internal.access.foreign.MemorySegmentProxy;
34import jdk.internal.misc.ScopedMemoryAccess.Scope;
35import jdk.internal.misc.VM;
36import jdk.internal.ref.Cleaner;
37import sun.nio.ch.DirectBuffer;
38
39
40class Direct$Type$Buffer$RW$$BO$
41#if[rw]
42    extends {#if[byte]?Mapped$Type$Buffer:$Type$Buffer}
43#else[rw]
44    extends Direct$Type$Buffer$BO$
45#end[rw]
46    implements DirectBuffer
47{
48
49#if[rw]
50
51    // Cached array base offset
52    private static final long ARRAY_BASE_OFFSET = 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 long address;
77        private long size;
78        private int capacity;
79
80        private Deallocator(long address, long size, int capacity) {
81            assert (address != 0);
82            this.address = address;
83            this.size = size;
84            this.capacity = capacity;
85        }
86
87        public void run() {
88            if (address == 0) {
89                // Paranoia
90                return;
91            }
92            UNSAFE.freeMemory(address);
93            address = 0;
94            Bits.unreserveMemory(size, capacity);
95        }
96
97    }
98
99    private final Cleaner cleaner;
100
101    public Cleaner cleaner() { return cleaner; }
102
103#else[byte]
104
105    public Cleaner cleaner() { return null; }
106
107#end[byte]
108
109#end[rw]
110
111#if[byte]
112
113    // Primary constructor
114    //
115    Direct$Type$Buffer$RW$(int cap) {                   // package-private
116#if[rw]
117        super(-1, 0, cap, cap, null);
118        boolean pa = VM.isDirectMemoryPageAligned();
119        int ps = Bits.pageSize();
120        long size = Math.max(1L, (long)cap + (pa ? ps : 0));
121        Bits.reserveMemory(size, cap);
122
123        long base = 0;
124        try {
125            base = UNSAFE.allocateMemory(size);
126        } catch (OutOfMemoryError x) {
127            Bits.unreserveMemory(size, cap);
128            throw x;
129        }
130        UNSAFE.setMemory(base, size, (byte) 0);
131        if (pa && (base % ps != 0)) {
132            // Round up to page boundary
133            address = base + ps - (base & (ps - 1));
134        } else {
135            address = base;
136        }
137        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
138        att = null;
139#else[rw]
140        super(cap);
141        this.isReadOnly = true;
142#end[rw]
143    }
144
145#if[rw]
146
147    // Invoked to construct a direct ByteBuffer referring to the block of
148    // memory. A given arbitrary object may also be attached to the buffer.
149    //
150    Direct$Type$Buffer(long addr, int cap, Object ob, MemorySegmentProxy segment) {
151        super(-1, 0, cap, cap, segment);
152        address = addr;
153        cleaner = null;
154        att = ob;
155    }
156
157    // Invoked to construct a direct ByteBuffer referring to the block of
158    // memory. A given arbitrary object may also be attached to the buffer.
159    //
160    Direct$Type$Buffer(long addr, int cap, Object ob, FileDescriptor fd, boolean isSync, MemorySegmentProxy segment) {
161        super(-1, 0, cap, cap, fd, isSync, segment);
162        address = addr;
163        cleaner = null;
164        att = ob;
165    }
166
167    // Invoked only by JNI: NewDirectByteBuffer(void*, long)
168    //
169    private Direct$Type$Buffer(long addr, int cap) {
170        super(-1, 0, cap, cap, null);
171        address = addr;
172        cleaner = null;
173        att = null;
174    }
175
176#end[rw]
177
178    // For memory-mapped buffers -- invoked by FileChannelImpl via reflection
179    //
180    protected Direct$Type$Buffer$RW$(int cap, long addr,
181                                     FileDescriptor fd,
182                                     Runnable unmapper,
183                                     boolean isSync, MemorySegmentProxy segment)
184    {
185#if[rw]
186        super(-1, 0, cap, cap, fd, isSync, segment);
187        address = addr;
188        cleaner = Cleaner.create(this, unmapper);
189        att = null;
190#else[rw]
191        super(cap, addr, fd, unmapper, isSync, segment);
192        this.isReadOnly = true;
193#end[rw]
194    }
195
196#end[byte]
197
198    // For duplicates and slices
199    //
200    Direct$Type$Buffer$RW$$BO$(DirectBuffer db,         // package-private
201                               int mark, int pos, int lim, int cap, int off,
202#if[byte]
203                               FileDescriptor fd, boolean isSync,
204#end[byte]
205                               MemorySegmentProxy segment)
206    {
207#if[rw]
208        super(mark, pos, lim, cap,
209#if[byte]
210              fd, isSync,
211#end[byte]
212              segment);
213        address = ((Buffer)db).address + off;
214#if[byte]
215        cleaner = null;
216#end[byte]
217        Object attachment = db.attachment();
218        att = (attachment == null ? db : attachment);
219#else[rw]
220        super(db, mark, pos, lim, cap, off,
221#if[byte]
222              fd, isSync,
223#end[byte]
224              segment);
225        this.isReadOnly = true;
226#end[rw]
227    }
228
229    @Override
230    Object base() {
231        return null;
232    }
233
234    public {#if[byte]?Mapped$Type$Buffer:$Type$Buffer} slice() {
235        int pos = this.position();
236        int lim = this.limit();
237        int rem = (pos <= lim ? lim - pos : 0);
238        int off = (pos << $LG_BYTES_PER_VALUE$);
239        assert (off >= 0);
240        return new Direct$Type$Buffer$RW$$BO$(this,
241                                              -1,
242                                              0,
243                                              rem,
244                                              rem,
245                                              off,
246#if[byte]
247                                              fileDescriptor(),
248                                              isSync(),
249#end[byte]
250                                              segment);
251    }
252
253    @Override
254    public {#if[byte]?Mapped$Type$Buffer:$Type$Buffer} slice(int index, int length) {
255        Objects.checkFromIndexSize(index, length, limit());
256        return new Direct$Type$Buffer$RW$$BO$(this,
257                                              -1,
258                                              0,
259                                              length,
260                                              length,
261                                              index << $LG_BYTES_PER_VALUE$,
262#if[byte]
263                                              fileDescriptor(),
264                                              isSync(),
265#end[byte]
266                                              segment);
267    }
268
269    public {#if[byte]?Mapped$Type$Buffer:$Type$Buffer} duplicate() {
270        return new Direct$Type$Buffer$RW$$BO$(this,
271                                              this.markValue(),
272                                              this.position(),
273                                              this.limit(),
274                                              this.capacity(),
275                                              0,
276#if[byte]
277                                              fileDescriptor(),
278                                              isSync(),
279#end[byte]
280                                              segment);
281    }
282
283    public $Type$Buffer asReadOnlyBuffer() {
284#if[rw]
285        return new Direct$Type$BufferR$BO$(this,
286                                           this.markValue(),
287                                           this.position(),
288                                           this.limit(),
289                                           this.capacity(),
290                                           0,
291#if[byte]
292                                           fileDescriptor(),
293                                           isSync(),
294#end[byte]
295                                           segment);
296#else[rw]
297        return duplicate();
298#end[rw]
299    }
300
301#if[rw]
302
303    public long address() {
304        Scope scope = scope();
305        if (scope != null) {
306            if (scope.ownerThread() == null) {
307                throw new UnsupportedOperationException("ByteBuffer derived from shared segments not supported");
308            }
309            try {
310                scope.checkValidState();
311            } catch (Scope.ScopedAccessError e) {
312                throw new IllegalStateException("This segment is already closed");
313            }
314        }
315        return address;
316    }
317
318    private long ix(int i) {
319        return address + ((long)i << $LG_BYTES_PER_VALUE$);
320    }
321
322    public $type$ get() {
323        try {
324            return $fromBits$($swap$(SCOPED_MEMORY_ACCESS.get$Swaptype$(scope(), null, ix(nextGetIndex()))));
325        } finally {
326            Reference.reachabilityFence(this);
327        }
328    }
329
330    public $type$ get(int i) {
331        try {
332            return $fromBits$($swap$(SCOPED_MEMORY_ACCESS.get$Swaptype$(scope(), null, ix(checkIndex(i)))));
333        } finally {
334            Reference.reachabilityFence(this);
335        }
336    }
337
338#if[streamableType]
339    $type$ getUnchecked(int i) {
340        try {
341            return $fromBits$($swap$(SCOPED_MEMORY_ACCESS.get$Swaptype$(null, null, ix(i))));
342        } finally {
343            Reference.reachabilityFence(this);
344        }
345    }
346#end[streamableType]
347#end[rw]
348
349    public $Type$Buffer put($type$ x) {
350#if[rw]
351        try {
352            SCOPED_MEMORY_ACCESS.put$Swaptype$(scope(), null, ix(nextPutIndex()), $swap$($toBits$(x)));
353        } finally {
354            Reference.reachabilityFence(this);
355        }
356        return this;
357#else[rw]
358        throw new ReadOnlyBufferException();
359#end[rw]
360    }
361
362    public $Type$Buffer put(int i, $type$ x) {
363#if[rw]
364        try {
365            SCOPED_MEMORY_ACCESS.put$Swaptype$(scope(), null, ix(checkIndex(i)), $swap$($toBits$(x)));
366        } finally {
367            Reference.reachabilityFence(this);
368        }
369        return this;
370#else[rw]
371        throw new ReadOnlyBufferException();
372#end[rw]
373    }
374
375    public {#if[byte]?Mapped$Type$Buffer:$Type$Buffer} compact() {
376#if[rw]
377        int pos = position();
378        int lim = limit();
379        assert (pos <= lim);
380        int rem = (pos <= lim ? lim - pos : 0);
381        try {
382            // null is passed as destination Scope to avoid checking scope() twice
383            SCOPED_MEMORY_ACCESS.copyMemory(scope(), null, null,
384                    ix(pos), null, ix(0), (long)rem << $LG_BYTES_PER_VALUE$);
385        } finally {
386            Reference.reachabilityFence(this);
387        }
388        position(rem);
389        limit(capacity());
390        discardMark();
391        return this;
392#else[rw]
393        throw new ReadOnlyBufferException();
394#end[rw]
395    }
396
397    public boolean isDirect() {
398        return true;
399    }
400
401    public boolean isReadOnly() {
402        return {#if[rw]?false:true};
403    }
404
405
406#if[char]
407
408    public String toString(int start, int end) {
409        Objects.checkFromToIndex(start, end, limit());
410        try {
411            int len = end - start;
412            char[] ca = new char[len];
413            CharBuffer cb = CharBuffer.wrap(ca);
414            CharBuffer db = this.duplicate();
415            db.position(start);
416            db.limit(end);
417            cb.put(db);
418            return new String(ca);
419        } catch (StringIndexOutOfBoundsException x) {
420            throw new IndexOutOfBoundsException();
421        }
422    }
423
424
425    // --- Methods to support CharSequence ---
426
427    public CharBuffer subSequence(int start, int end) {
428        int pos = position();
429        int lim = limit();
430        assert (pos <= lim);
431        pos = (pos <= lim ? pos : lim);
432        int len = lim - pos;
433
434        Objects.checkFromToIndex(start, end, len);
435        return new DirectCharBuffer$RW$$BO$(this,
436                                            -1,
437                                            pos + start,
438                                            pos + end,
439                                            capacity(),
440                                            offset, segment);
441    }
442
443#end[char]
444
445
446
447#if[!byte]
448
449    public ByteOrder order() {
450#if[boS]
451        return ((ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
452                ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
453#end[boS]
454#if[boU]
455        return ((ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN)
456                ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
457#end[boU]
458    }
459
460#end[!byte]
461
462#if[char]
463    ByteOrder charRegionOrder() {
464        return order();
465    }
466#end[char]
467
468
469#if[byte]
470    // #BIN
471    //
472    // Binary-data access methods  for short, char, int, long, float,
473    // and double will be inserted here
474
475#end[byte]
476
477}
478