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