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