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