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         att = db;
 198 #else[rw]
 199         super(db, mark, pos, lim, cap, off);
 200         this.isReadOnly = true;
 201 #end[rw]
 202     }
 203 
 204     @Override
 205     Object base() {
 206         return null;
 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         try {
 262             return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(nextGetIndex()))));
 263         } finally {
 264             Reference.reachabilityFence(this);
 265         }
 266     }
 267 
 268     public $type$ get(int i) {
 269         try {
 270             return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(checkIndex(i)))));
 271         } finally {
 272             Reference.reachabilityFence(this);
 273         }
 274     }
 275 
 276 #if[streamableType]
 277     $type$ getUnchecked(int i) {
 278         try {
 279             return $fromBits$($swap$(UNSAFE.get$Swaptype$(ix(i))));
 280         } finally {
 281             Reference.reachabilityFence(this);
 282         }
 283     }
 284 #end[streamableType]
 285 
 286     public $Type$Buffer get($type$[] dst, int offset, int length) {
 287 #if[rw]
 288         if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
 289             checkBounds(offset, length, dst.length);
 290             int pos = position();
 291             int lim = limit();
 292             assert (pos <= lim);
 293             int rem = (pos <= lim ? lim - pos : 0);
 294             if (length > rem)
 295                 throw new BufferUnderflowException();
 296 
 297             long dstOffset = ARRAY_BASE_OFFSET + ((long)offset << $LG_BYTES_PER_VALUE$);
 298             try {
 299 #if[!byte]
 300                 if (order() != ByteOrder.nativeOrder())
 301                     UNSAFE.copySwapMemory(null,
 302                                           ix(pos),
 303                                           dst,
 304                                           dstOffset,
 305                                           (long)length << $LG_BYTES_PER_VALUE$,
 306                                           (long)1 << $LG_BYTES_PER_VALUE$);
 307                 else
 308 #end[!byte]
 309                     UNSAFE.copyMemory(null,
 310                                       ix(pos),
 311                                       dst,
 312                                       dstOffset,
 313                                       (long)length << $LG_BYTES_PER_VALUE$);
 314             } finally {
 315                 Reference.reachabilityFence(this);
 316             }
 317             position(pos + length);
 318         } else {
 319             super.get(dst, offset, length);
 320         }
 321         return this;
 322 #else[rw]
 323         throw new ReadOnlyBufferException();
 324 #end[rw]
 325     }
 326 
 327 #end[rw]
 328 
 329     public $Type$Buffer put($type$ x) {
 330 #if[rw]
 331         try {
 332             UNSAFE.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
 333         } finally {
 334             Reference.reachabilityFence(this);
 335         }
 336         return this;
 337 #else[rw]
 338         throw new ReadOnlyBufferException();
 339 #end[rw]
 340     }
 341 
 342     public $Type$Buffer put(int i, $type$ x) {
 343 #if[rw]
 344         try {
 345             UNSAFE.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
 346         } finally {
 347             Reference.reachabilityFence(this);
 348         }
 349         return this;
 350 #else[rw]
 351         throw new ReadOnlyBufferException();
 352 #end[rw]
 353     }
 354 
 355     public $Type$Buffer put($Type$Buffer src) {
 356 #if[rw]
 357         if (src instanceof Direct$Type$Buffer$BO$) {
 358             if (src == this)
 359                 throw createSameBufferException();
 360             Direct$Type$Buffer$RW$$BO$ sb = (Direct$Type$Buffer$RW$$BO$)src;
 361 
 362             int spos = sb.position();
 363             int slim = sb.limit();
 364             assert (spos <= slim);
 365             int srem = (spos <= slim ? slim - spos : 0);
 366 
 367             int pos = position();
 368             int lim = limit();
 369             assert (pos <= lim);
 370             int rem = (pos <= lim ? lim - pos : 0);
 371 
 372             if (srem > rem)
 373                 throw new BufferOverflowException();
 374             try {
 375                 UNSAFE.copyMemory(sb.ix(spos), ix(pos), (long)srem << $LG_BYTES_PER_VALUE$);
 376             } finally {
 377                 Reference.reachabilityFence(sb);
 378                 Reference.reachabilityFence(this);
 379             }
 380             sb.position(spos + srem);
 381             position(pos + srem);
 382         } else if (src.hb != null) {
 383 
 384             int spos = src.position();
 385             int slim = src.limit();
 386             assert (spos <= slim);
 387             int srem = (spos <= slim ? slim - spos : 0);
 388 
 389             put(src.hb, src.offset + spos, srem);
 390             src.position(spos + srem);
 391 
 392         } else {
 393             super.put(src);
 394         }
 395         return this;
 396 #else[rw]
 397         throw new ReadOnlyBufferException();
 398 #end[rw]
 399     }
 400 
 401     public $Type$Buffer put($type$[] src, int offset, int length) {
 402 #if[rw]
 403         if (((long)length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
 404             checkBounds(offset, length, src.length);
 405             int pos = position();
 406             int lim = limit();
 407             assert (pos <= lim);
 408             int rem = (pos <= lim ? lim - pos : 0);
 409             if (length > rem)
 410                 throw new BufferOverflowException();
 411 
 412             long srcOffset = ARRAY_BASE_OFFSET + ((long)offset << $LG_BYTES_PER_VALUE$);
 413             try {
 414 #if[!byte]
 415                 if (order() != ByteOrder.nativeOrder())
 416                     UNSAFE.copySwapMemory(src,
 417                                           srcOffset,
 418                                           null,
 419                                           ix(pos),
 420                                           (long)length << $LG_BYTES_PER_VALUE$,
 421                                           (long)1 << $LG_BYTES_PER_VALUE$);
 422                 else
 423 #end[!byte]
 424                     UNSAFE.copyMemory(src,
 425                                       srcOffset,
 426                                       null,
 427                                       ix(pos),
 428                                       (long)length << $LG_BYTES_PER_VALUE$);
 429             } finally {
 430                 Reference.reachabilityFence(this);
 431             }
 432             position(pos + length);
 433         } else {
 434             super.put(src, offset, length);
 435         }
 436         return this;
 437 #else[rw]
 438         throw new ReadOnlyBufferException();
 439 #end[rw]
 440     }
 441 
 442     public $Type$Buffer compact() {
 443 #if[rw]
 444         int pos = position();
 445         int lim = limit();
 446         assert (pos <= lim);
 447         int rem = (pos <= lim ? lim - pos : 0);
 448         try {
 449             UNSAFE.copyMemory(ix(pos), ix(0), (long)rem << $LG_BYTES_PER_VALUE$);
 450         } finally {
 451             Reference.reachabilityFence(this);
 452         }
 453         position(rem);
 454         limit(capacity());
 455         discardMark();
 456         return this;
 457 #else[rw]
 458         throw new ReadOnlyBufferException();
 459 #end[rw]
 460     }
 461 
 462     public boolean isDirect() {
 463         return true;
 464     }
 465 
 466     public boolean isReadOnly() {
 467         return {#if[rw]?false:true};
 468     }
 469 
 470 
 471 #if[char]
 472 
 473     public String toString(int start, int end) {
 474         if ((end > limit()) || (start > end))
 475             throw new IndexOutOfBoundsException();
 476         try {
 477             int len = end - start;
 478             char[] ca = new char[len];
 479             CharBuffer cb = CharBuffer.wrap(ca);
 480             CharBuffer db = this.duplicate();
 481             db.position(start);
 482             db.limit(end);
 483             cb.put(db);
 484             return new String(ca);
 485         } catch (StringIndexOutOfBoundsException x) {
 486             throw new IndexOutOfBoundsException();
 487         }
 488     }
 489 
 490 
 491     // --- Methods to support CharSequence ---
 492 
 493     public CharBuffer subSequence(int start, int end) {
 494         int pos = position();
 495         int lim = limit();
 496         assert (pos <= lim);
 497         pos = (pos <= lim ? pos : lim);
 498         int len = lim - pos;
 499 
 500         if ((start < 0) || (end > len) || (start > end))
 501             throw new IndexOutOfBoundsException();
 502         return new DirectCharBuffer$RW$$BO$(this,
 503                                             -1,
 504                                             pos + start,
 505                                             pos + end,
 506                                             capacity(),
 507                                             offset);
 508     }
 509 
 510 #end[char]
 511 
 512 
 513 
 514 #if[!byte]
 515 
 516     public ByteOrder order() {
 517 #if[boS]
 518         return ((ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
 519                 ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
 520 #end[boS]
 521 #if[boU]
 522         return ((ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN)
 523                 ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
 524 #end[boU]
 525     }
 526 
 527 #end[!byte]
 528 
 529 #if[char]
 530     ByteOrder charRegionOrder() {
 531         return order();
 532     }
 533 #end[char]
 534 
 535 
 536 #if[byte]
 537     // #BIN
 538     //
 539     // Binary-data access methods  for short, char, int, long, float,
 540     // and double will be inserted here
 541 
 542 #end[byte]
 543 
 544 }