1 /*
   2  * Copyright 2000-2008 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 #warn This file is preprocessed before being compiled
  27 
  28 package java.nio;
  29 
  30 import sun.misc.Cleaner;
  31 import sun.misc.Unsafe;
  32 import sun.nio.ch.DirectBuffer;
  33 import sun.nio.ch.FileChannelImpl;
  34 
  35 
  36 class Direct$Type$Buffer$RW$$BO$
  37 #if[rw]
  38     extends {#if[byte]?Mapped$Type$Buffer:$Type$Buffer}
  39 #else[rw]
  40     extends Direct$Type$Buffer$BO$
  41 #end[rw]
  42     implements DirectBuffer
  43 {
  44 
  45 #if[rw]
  46 
  47     // Cached unsafe-access object
  48     protected static final Unsafe unsafe = Bits.unsafe();
  49 
  50     // Cached array base offset
  51     private static final long arrayBaseOffset = (long)unsafe.arrayBaseOffset($type$[].class);
  52 
  53     // Cached unaligned-access capability
  54     protected static final boolean unaligned = Bits.unaligned();
  55 
  56     // Base address, used in all indexing calculations
  57     // NOTE: moved up to Buffer.java for speed in JNI GetDirectBufferAddress
  58     //    protected long address;
  59 
  60     // If this buffer is a view of another buffer then we keep a reference to
  61     // that buffer so that its memory isn't freed before we're done with it
  62     protected Object viewedBuffer = null;
  63 
  64     public Object viewedBuffer() {
  65         return viewedBuffer;
  66     }
  67 
  68 #if[byte]
  69 
  70     private static class Deallocator
  71         implements Runnable
  72     {
  73 
  74         private static Unsafe unsafe = Unsafe.getUnsafe();
  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, false);
 118         int ps = Bits.pageSize();
 119         int size = cap + ps;
 120         Bits.reserveMemory(size, cap);
 121 
 122         long base = 0;
 123         try {
 124             base = unsafe.allocateMemory(size);
 125         } catch (OutOfMemoryError x) {
 126             Bits.unreserveMemory(size, cap);
 127             throw x;
 128         }
 129         unsafe.setMemory(base, size, (byte) 0);
 130         if (base % ps != 0) {
 131             // Round up to page boundary
 132             address = base + ps - (base & (ps - 1));
 133         } else {
 134             address = base;
 135         }
 136         cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
 137 #else[rw]
 138         super(cap);
 139 #end[rw]
 140     }
 141 
 142 #if[rw]
 143 
 144     // Invoked only by JNI: NewDirectByteBuffer(void*, long)
 145     //
 146     private Direct$Type$Buffer(long addr, int cap) {
 147         super(-1, 0, cap, cap, false);
 148         address = addr;
 149         cleaner = null;
 150     }
 151 
 152 #end[rw]
 153 
 154     // For memory-mapped buffers -- invoked by FileChannelImpl via reflection
 155     //
 156     protected Direct$Type$Buffer$RW$(int cap, long addr, Runnable unmapper) {
 157 #if[rw]
 158         super(-1, 0, cap, cap, true);
 159         address = addr;
 160         viewedBuffer = null;
 161         cleaner = Cleaner.create(this, unmapper);
 162 #else[rw]
 163         super(cap, addr, unmapper);
 164 #end[rw]
 165     }
 166 
 167 #end[byte]
 168 
 169     // For duplicates and slices
 170     //
 171     Direct$Type$Buffer$RW$$BO$(DirectBuffer db,         // package-private
 172                                int mark, int pos, int lim, int cap,
 173                                int off)
 174     {
 175 #if[rw]
 176         super(mark, pos, lim, cap);
 177         address = db.address() + off;
 178         viewedBuffer = db;
 179 #if[byte]
 180         cleaner = null;
 181 #end[byte]
 182 #else[rw]
 183         super(db, mark, pos, lim, cap, off);
 184 #end[rw]
 185     }
 186 
 187     public $Type$Buffer slice() {
 188         int pos = this.position();
 189         int lim = this.limit();
 190         assert (pos <= lim);
 191         int rem = (pos <= lim ? lim - pos : 0);
 192         int off = (pos << $LG_BYTES_PER_VALUE$);
 193         assert (off >= 0);
 194         return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off);
 195     }
 196 
 197     public $Type$Buffer duplicate() {
 198         return new Direct$Type$Buffer$RW$$BO$(this,
 199                                               this.markValue(),
 200                                               this.position(),
 201                                               this.limit(),
 202                                               this.capacity(),
 203                                               0);
 204     }
 205 
 206     public $Type$Buffer asReadOnlyBuffer() {
 207 #if[rw]
 208         return new Direct$Type$BufferR$BO$(this,
 209                                            this.markValue(),
 210                                            this.position(),
 211                                            this.limit(),
 212                                            this.capacity(),
 213                                            0);
 214 #else[rw]
 215         return duplicate();
 216 #end[rw]
 217     }
 218 
 219 #if[rw]
 220 
 221     public long address() {
 222         return address;
 223     }
 224 
 225     private long ix(int i) {
 226         return address + (i << $LG_BYTES_PER_VALUE$);
 227     }
 228 
 229     public $type$ get() {
 230         return $fromBits$($swap$(unsafe.get$Swaptype$(ix(nextGetIndex()))));
 231     }
 232 
 233     public $type$ get(int i) {
 234         return $fromBits$($swap$(unsafe.get$Swaptype$(ix(checkIndex(i)))));
 235     }
 236 
 237     public $Type$Buffer get($type$[] dst, int offset, int length) {
 238 #if[rw]
 239         if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_TO_ARRAY_THRESHOLD) {
 240             checkBounds(offset, length, dst.length);
 241             int pos = position();
 242             int lim = limit();
 243             assert (pos <= lim);
 244             int rem = (pos <= lim ? lim - pos : 0);
 245             if (length > rem)
 246                 throw new BufferUnderflowException();
 247 
 248 #if[!byte]
 249             if (order() != ByteOrder.nativeOrder())
 250                 Bits.copyTo$Memtype$Array(ix(pos), dst,
 251                                           offset << $LG_BYTES_PER_VALUE$,
 252                                           length << $LG_BYTES_PER_VALUE$);
 253             else
 254 #end[!byte]
 255                 Bits.copyToArray(ix(pos), dst, arrayBaseOffset,
 256                                  offset << $LG_BYTES_PER_VALUE$,
 257                                  length << $LG_BYTES_PER_VALUE$);
 258             position(pos + length);
 259         } else {
 260             super.get(dst, offset, length);
 261         }
 262         return this;
 263 #else[rw]
 264         throw new ReadOnlyBufferException();
 265 #end[rw]
 266     }
 267 
 268 #end[rw]
 269 
 270     public $Type$Buffer put($type$ x) {
 271 #if[rw]
 272         unsafe.put$Swaptype$(ix(nextPutIndex()), $swap$($toBits$(x)));
 273         return this;
 274 #else[rw]
 275         throw new ReadOnlyBufferException();
 276 #end[rw]
 277     }
 278 
 279     public $Type$Buffer put(int i, $type$ x) {
 280 #if[rw]
 281         unsafe.put$Swaptype$(ix(checkIndex(i)), $swap$($toBits$(x)));
 282         return this;
 283 #else[rw]
 284         throw new ReadOnlyBufferException();
 285 #end[rw]
 286     }
 287 
 288     public $Type$Buffer put($Type$Buffer src) {
 289 #if[rw]
 290         if (src instanceof Direct$Type$Buffer$BO$) {
 291             if (src == this)
 292                 throw new IllegalArgumentException();
 293             Direct$Type$Buffer$RW$$BO$ sb = (Direct$Type$Buffer$RW$$BO$)src;
 294 
 295             int spos = sb.position();
 296             int slim = sb.limit();
 297             assert (spos <= slim);
 298             int srem = (spos <= slim ? slim - spos : 0);
 299 
 300             int pos = position();
 301             int lim = limit();
 302             assert (pos <= lim);
 303             int rem = (pos <= lim ? lim - pos : 0);
 304 
 305             if (srem > rem)
 306                 throw new BufferOverflowException();
 307             unsafe.copyMemory(sb.ix(spos), ix(pos), srem << $LG_BYTES_PER_VALUE$);
 308             sb.position(spos + srem);
 309             position(pos + srem);
 310         } else if (src.hb != null) {
 311 
 312             int spos = src.position();
 313             int slim = src.limit();
 314             assert (spos <= slim);
 315             int srem = (spos <= slim ? slim - spos : 0);
 316 
 317             put(src.hb, src.offset + spos, srem);
 318             src.position(spos + srem);
 319 
 320         } else {
 321             super.put(src);
 322         }
 323         return this;
 324 #else[rw]
 325         throw new ReadOnlyBufferException();
 326 #end[rw]
 327     }
 328 
 329     public $Type$Buffer put($type$[] src, int offset, int length) {
 330 #if[rw]
 331         if ((length << $LG_BYTES_PER_VALUE$) > Bits.JNI_COPY_FROM_ARRAY_THRESHOLD) {
 332             checkBounds(offset, length, src.length);
 333             int pos = position();
 334             int lim = limit();
 335             assert (pos <= lim);
 336             int rem = (pos <= lim ? lim - pos : 0);
 337             if (length > rem)
 338                 throw new BufferOverflowException();
 339 
 340 #if[!byte]
 341             if (order() != ByteOrder.nativeOrder())
 342                 Bits.copyFrom$Memtype$Array(src, offset << $LG_BYTES_PER_VALUE$,
 343                                             ix(pos), length << $LG_BYTES_PER_VALUE$);
 344             else
 345 #end[!byte]
 346                 Bits.copyFromArray(src, arrayBaseOffset, offset << $LG_BYTES_PER_VALUE$,
 347                                    ix(pos), length << $LG_BYTES_PER_VALUE$);
 348             position(pos + length);
 349         } else {
 350             super.put(src, offset, length);
 351         }
 352         return this;
 353 #else[rw]
 354         throw new ReadOnlyBufferException();
 355 #end[rw]
 356     }
 357 
 358     public $Type$Buffer compact() {
 359 #if[rw]
 360         int pos = position();
 361         int lim = limit();
 362         assert (pos <= lim);
 363         int rem = (pos <= lim ? lim - pos : 0);
 364 
 365         unsafe.copyMemory(ix(pos), ix(0), rem << $LG_BYTES_PER_VALUE$);
 366         position(rem);
 367         limit(capacity());
 368         discardMark();
 369         return this;
 370 #else[rw]
 371         throw new ReadOnlyBufferException();
 372 #end[rw]
 373     }
 374 
 375     public boolean isDirect() {
 376         return true;
 377     }
 378 
 379     public boolean isReadOnly() {
 380         return {#if[rw]?false:true};
 381     }
 382 
 383 
 384 #if[char]
 385 
 386     public String toString(int start, int end) {
 387         if ((end > limit()) || (start > end))
 388             throw new IndexOutOfBoundsException();
 389         try {
 390             int len = end - start;
 391             char[] ca = new char[len];
 392             CharBuffer cb = CharBuffer.wrap(ca);
 393             CharBuffer db = this.duplicate();
 394             db.position(start);
 395             db.limit(end);
 396             cb.put(db);
 397             return new String(ca);
 398         } catch (StringIndexOutOfBoundsException x) {
 399             throw new IndexOutOfBoundsException();
 400         }
 401     }
 402 
 403 
 404     // --- Methods to support CharSequence ---
 405 
 406     public CharBuffer subSequence(int start, int end) {
 407         int pos = position();
 408         int lim = limit();
 409         assert (pos <= lim);
 410         pos = (pos <= lim ? pos : lim);
 411         int len = lim - pos;
 412 
 413         if ((start < 0) || (end > len) || (start > end))
 414             throw new IndexOutOfBoundsException();
 415         int sublen = end - start;
 416         int off = (pos + start) << $LG_BYTES_PER_VALUE$;
 417         assert (off >= 0);
 418         return new DirectCharBuffer$RW$$BO$(this, -1, 0, sublen, sublen, off);
 419     }
 420 
 421 #end[char]
 422 
 423 
 424 
 425 #if[!byte]
 426 
 427     public ByteOrder order() {
 428 #if[boS]
 429         return ((ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN)
 430                 ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
 431 #end[boS]
 432 #if[boU]
 433         return ((ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN)
 434                 ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN);
 435 #end[boU]
 436     }
 437 
 438 #end[!byte]
 439 
 440 
 441 
 442 #if[byte]
 443 
 444     byte _get(int i) {                          // package-private
 445         return unsafe.getByte(address + i);
 446     }
 447 
 448     void _put(int i, byte b) {                  // package-private
 449 #if[rw]
 450         unsafe.putByte(address + i, b);
 451 #else[rw]
 452         throw new ReadOnlyBufferException();
 453 #end[rw]
 454     }
 455 
 456     // #BIN
 457     //
 458     // Binary-data access methods  for short, char, int, long, float,
 459     // and double will be inserted here
 460 
 461 #end[byte]
 462 
 463 }