Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/nio/ch/Util.java
41159 views
1
/*
2
* Copyright (c) 2000, 2021, 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
package sun.nio.ch;
27
28
import java.io.FileDescriptor;
29
import java.io.IOException;
30
import java.lang.reflect.Constructor;
31
import java.lang.reflect.InvocationTargetException;
32
import java.nio.ByteBuffer;
33
import java.nio.MappedByteBuffer;
34
import java.security.AccessController;
35
import java.security.PrivilegedAction;
36
import java.util.Collection;
37
import java.util.Iterator;
38
import java.util.Set;
39
40
import jdk.internal.access.foreign.MemorySegmentProxy;
41
import jdk.internal.misc.TerminatingThreadLocal;
42
import jdk.internal.misc.Unsafe;
43
import sun.security.action.GetPropertyAction;
44
45
public class Util {
46
47
// -- Caches --
48
49
// The number of temp buffers in our pool
50
private static final int TEMP_BUF_POOL_SIZE = IOUtil.IOV_MAX;
51
52
// The max size allowed for a cached temp buffer, in bytes
53
private static final long MAX_CACHED_BUFFER_SIZE = getMaxCachedBufferSize();
54
55
// Per-thread cache of temporary direct buffers
56
private static ThreadLocal<BufferCache> bufferCache = new TerminatingThreadLocal<>() {
57
@Override
58
protected BufferCache initialValue() {
59
return new BufferCache();
60
}
61
@Override
62
protected void threadTerminated(BufferCache cache) { // will never be null
63
while (!cache.isEmpty()) {
64
ByteBuffer bb = cache.removeFirst();
65
free(bb);
66
}
67
}
68
};
69
70
/**
71
* Returns the max size allowed for a cached temp buffers, in
72
* bytes. It defaults to Long.MAX_VALUE. It can be set with the
73
* jdk.nio.maxCachedBufferSize property. Even though
74
* ByteBuffer.capacity() returns an int, we're using a long here
75
* for potential future-proofing.
76
*/
77
private static long getMaxCachedBufferSize() {
78
String s = GetPropertyAction
79
.privilegedGetProperty("jdk.nio.maxCachedBufferSize");
80
if (s != null) {
81
try {
82
long m = Long.parseLong(s);
83
if (m >= 0) {
84
return m;
85
} else {
86
// if it's negative, ignore the system property
87
}
88
} catch (NumberFormatException e) {
89
// if the string is not well formed, ignore the system property
90
}
91
}
92
return Long.MAX_VALUE;
93
}
94
95
/**
96
* Returns true if a buffer of this size is too large to be
97
* added to the buffer cache, false otherwise.
98
*/
99
private static boolean isBufferTooLarge(int size) {
100
return size > MAX_CACHED_BUFFER_SIZE;
101
}
102
103
/**
104
* Returns true if the buffer is too large to be added to the
105
* buffer cache, false otherwise.
106
*/
107
private static boolean isBufferTooLarge(ByteBuffer buf) {
108
return isBufferTooLarge(buf.capacity());
109
}
110
111
/**
112
* A simple cache of direct buffers.
113
*/
114
private static class BufferCache {
115
// the array of buffers
116
private ByteBuffer[] buffers;
117
118
// the number of buffers in the cache
119
private int count;
120
121
// the index of the first valid buffer (undefined if count == 0)
122
private int start;
123
124
private int next(int i) {
125
return (i + 1) % TEMP_BUF_POOL_SIZE;
126
}
127
128
BufferCache() {
129
buffers = new ByteBuffer[TEMP_BUF_POOL_SIZE];
130
}
131
132
/**
133
* Removes and returns a buffer from the cache of at least the given
134
* size (or null if no suitable buffer is found).
135
*/
136
ByteBuffer get(int size) {
137
// Don't call this if the buffer would be too large.
138
assert !isBufferTooLarge(size);
139
140
if (count == 0)
141
return null; // cache is empty
142
143
ByteBuffer[] buffers = this.buffers;
144
145
// search for suitable buffer (often the first buffer will do)
146
ByteBuffer buf = buffers[start];
147
if (buf.capacity() < size) {
148
buf = null;
149
int i = start;
150
while ((i = next(i)) != start) {
151
ByteBuffer bb = buffers[i];
152
if (bb == null)
153
break;
154
if (bb.capacity() >= size) {
155
buf = bb;
156
break;
157
}
158
}
159
if (buf == null)
160
return null;
161
// move first element to here to avoid re-packing
162
buffers[i] = buffers[start];
163
}
164
165
// remove first element
166
buffers[start] = null;
167
start = next(start);
168
count--;
169
170
// prepare the buffer and return it
171
buf.rewind();
172
buf.limit(size);
173
return buf;
174
}
175
176
boolean offerFirst(ByteBuffer buf) {
177
// Don't call this if the buffer is too large.
178
assert !isBufferTooLarge(buf);
179
180
if (count >= TEMP_BUF_POOL_SIZE) {
181
return false;
182
} else {
183
start = (start + TEMP_BUF_POOL_SIZE - 1) % TEMP_BUF_POOL_SIZE;
184
buffers[start] = buf;
185
count++;
186
return true;
187
}
188
}
189
190
boolean offerLast(ByteBuffer buf) {
191
// Don't call this if the buffer is too large.
192
assert !isBufferTooLarge(buf);
193
194
if (count >= TEMP_BUF_POOL_SIZE) {
195
return false;
196
} else {
197
int next = (start + count) % TEMP_BUF_POOL_SIZE;
198
buffers[next] = buf;
199
count++;
200
return true;
201
}
202
}
203
204
boolean isEmpty() {
205
return count == 0;
206
}
207
208
ByteBuffer removeFirst() {
209
assert count > 0;
210
ByteBuffer buf = buffers[start];
211
buffers[start] = null;
212
start = next(start);
213
count--;
214
return buf;
215
}
216
}
217
218
/**
219
* Returns a temporary buffer of at least the given size
220
*/
221
public static ByteBuffer getTemporaryDirectBuffer(int size) {
222
// If a buffer of this size is too large for the cache, there
223
// should not be a buffer in the cache that is at least as
224
// large. So we'll just create a new one. Also, we don't have
225
// to remove the buffer from the cache (as this method does
226
// below) given that we won't put the new buffer in the cache.
227
if (isBufferTooLarge(size)) {
228
return ByteBuffer.allocateDirect(size);
229
}
230
231
BufferCache cache = bufferCache.get();
232
ByteBuffer buf = cache.get(size);
233
if (buf != null) {
234
return buf;
235
} else {
236
// No suitable buffer in the cache so we need to allocate a new
237
// one. To avoid the cache growing then we remove the first
238
// buffer from the cache and free it.
239
if (!cache.isEmpty()) {
240
buf = cache.removeFirst();
241
free(buf);
242
}
243
return ByteBuffer.allocateDirect(size);
244
}
245
}
246
247
/**
248
* Returns a temporary buffer of at least the given size and
249
* aligned to the alignment
250
*/
251
public static ByteBuffer getTemporaryAlignedDirectBuffer(int size,
252
int alignment) {
253
if (isBufferTooLarge(size)) {
254
return ByteBuffer.allocateDirect(size + alignment - 1)
255
.alignedSlice(alignment);
256
}
257
258
BufferCache cache = bufferCache.get();
259
ByteBuffer buf = cache.get(size);
260
if (buf != null) {
261
if (buf.alignmentOffset(0, alignment) == 0) {
262
return buf;
263
}
264
} else {
265
if (!cache.isEmpty()) {
266
buf = cache.removeFirst();
267
free(buf);
268
}
269
}
270
return ByteBuffer.allocateDirect(size + alignment - 1)
271
.alignedSlice(alignment);
272
}
273
274
/**
275
* Releases a temporary buffer by returning to the cache or freeing it.
276
*/
277
public static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
278
offerFirstTemporaryDirectBuffer(buf);
279
}
280
281
/**
282
* Releases a temporary buffer by returning to the cache or freeing it. If
283
* returning to the cache then insert it at the start so that it is
284
* likely to be returned by a subsequent call to getTemporaryDirectBuffer.
285
*/
286
static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
287
// If the buffer is too large for the cache we don't have to
288
// check the cache. We'll just free it.
289
if (isBufferTooLarge(buf)) {
290
free(buf);
291
return;
292
}
293
294
assert buf != null;
295
BufferCache cache = bufferCache.get();
296
if (!cache.offerFirst(buf)) {
297
// cache is full
298
free(buf);
299
}
300
}
301
302
/**
303
* Releases a temporary buffer by returning to the cache or freeing it. If
304
* returning to the cache then insert it at the end. This makes it
305
* suitable for scatter/gather operations where the buffers are returned to
306
* cache in same order that they were obtained.
307
*/
308
static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
309
// If the buffer is too large for the cache we don't have to
310
// check the cache. We'll just free it.
311
if (isBufferTooLarge(buf)) {
312
free(buf);
313
return;
314
}
315
316
assert buf != null;
317
BufferCache cache = bufferCache.get();
318
if (!cache.offerLast(buf)) {
319
// cache is full
320
free(buf);
321
}
322
}
323
324
/**
325
* Frees the memory for the given direct buffer
326
*/
327
private static void free(ByteBuffer buf) {
328
((DirectBuffer)buf).cleaner().clean();
329
}
330
331
332
// -- Random stuff --
333
334
static ByteBuffer[] subsequence(ByteBuffer[] bs, int offset, int length) {
335
if ((offset == 0) && (length == bs.length))
336
return bs;
337
int n = length;
338
ByteBuffer[] bs2 = new ByteBuffer[n];
339
for (int i = 0; i < n; i++)
340
bs2[i] = bs[offset + i];
341
return bs2;
342
}
343
344
static <E> Set<E> ungrowableSet(final Set<E> s) {
345
return new Set<E>() {
346
347
public int size() { return s.size(); }
348
public boolean isEmpty() { return s.isEmpty(); }
349
public boolean contains(Object o) { return s.contains(o); }
350
public Object[] toArray() { return s.toArray(); }
351
public <T> T[] toArray(T[] a) { return s.toArray(a); }
352
public String toString() { return s.toString(); }
353
public Iterator<E> iterator() { return s.iterator(); }
354
public boolean equals(Object o) { return s.equals(o); }
355
public int hashCode() { return s.hashCode(); }
356
public void clear() { s.clear(); }
357
public boolean remove(Object o) { return s.remove(o); }
358
359
public boolean containsAll(Collection<?> coll) {
360
return s.containsAll(coll);
361
}
362
public boolean removeAll(Collection<?> coll) {
363
return s.removeAll(coll);
364
}
365
public boolean retainAll(Collection<?> coll) {
366
return s.retainAll(coll);
367
}
368
369
public boolean add(E o){
370
throw new UnsupportedOperationException();
371
}
372
public boolean addAll(Collection<? extends E> coll) {
373
throw new UnsupportedOperationException();
374
}
375
376
};
377
}
378
379
380
// -- Unsafe access --
381
382
private static Unsafe unsafe = Unsafe.getUnsafe();
383
384
private static byte _get(long a) {
385
return unsafe.getByte(a);
386
}
387
388
private static void _put(long a, byte b) {
389
unsafe.putByte(a, b);
390
}
391
392
static void erase(ByteBuffer bb) {
393
unsafe.setMemory(((DirectBuffer)bb).address(), bb.capacity(), (byte)0);
394
}
395
396
static Unsafe unsafe() {
397
return unsafe;
398
}
399
400
private static int pageSize = -1;
401
402
static int pageSize() {
403
if (pageSize == -1)
404
pageSize = unsafe().pageSize();
405
return pageSize;
406
}
407
408
private static volatile Constructor<?> directByteBufferConstructor;
409
410
@SuppressWarnings("removal")
411
private static void initDBBConstructor() {
412
AccessController.doPrivileged(new PrivilegedAction<Void>() {
413
public Void run() {
414
try {
415
Class<?> cl = Class.forName("java.nio.DirectByteBuffer");
416
Constructor<?> ctor = cl.getDeclaredConstructor(
417
new Class<?>[] { int.class,
418
long.class,
419
FileDescriptor.class,
420
Runnable.class,
421
boolean.class, MemorySegmentProxy.class});
422
ctor.setAccessible(true);
423
directByteBufferConstructor = ctor;
424
} catch (ClassNotFoundException |
425
NoSuchMethodException |
426
IllegalArgumentException |
427
ClassCastException x) {
428
throw new InternalError(x);
429
}
430
return null;
431
}});
432
}
433
434
static MappedByteBuffer newMappedByteBuffer(int size, long addr,
435
FileDescriptor fd,
436
Runnable unmapper,
437
boolean isSync)
438
{
439
MappedByteBuffer dbb;
440
if (directByteBufferConstructor == null)
441
initDBBConstructor();
442
try {
443
dbb = (MappedByteBuffer)directByteBufferConstructor.newInstance(
444
new Object[] { size,
445
addr,
446
fd,
447
unmapper,
448
isSync, null});
449
} catch (InstantiationException |
450
IllegalAccessException |
451
InvocationTargetException e) {
452
throw new InternalError(e);
453
}
454
return dbb;
455
}
456
457
private static volatile Constructor<?> directByteBufferRConstructor;
458
459
@SuppressWarnings("removal")
460
private static void initDBBRConstructor() {
461
AccessController.doPrivileged(new PrivilegedAction<Void>() {
462
public Void run() {
463
try {
464
Class<?> cl = Class.forName("java.nio.DirectByteBufferR");
465
Constructor<?> ctor = cl.getDeclaredConstructor(
466
new Class<?>[] { int.class,
467
long.class,
468
FileDescriptor.class,
469
Runnable.class,
470
boolean.class, MemorySegmentProxy.class });
471
ctor.setAccessible(true);
472
directByteBufferRConstructor = ctor;
473
} catch (ClassNotFoundException |
474
NoSuchMethodException |
475
IllegalArgumentException |
476
ClassCastException x) {
477
throw new InternalError(x);
478
}
479
return null;
480
}});
481
}
482
483
static MappedByteBuffer newMappedByteBufferR(int size, long addr,
484
FileDescriptor fd,
485
Runnable unmapper,
486
boolean isSync)
487
{
488
MappedByteBuffer dbb;
489
if (directByteBufferRConstructor == null)
490
initDBBRConstructor();
491
try {
492
dbb = (MappedByteBuffer)directByteBufferRConstructor.newInstance(
493
new Object[] { size,
494
addr,
495
fd,
496
unmapper,
497
isSync, null});
498
} catch (InstantiationException |
499
IllegalAccessException |
500
InvocationTargetException e) {
501
throw new InternalError(e);
502
}
503
return dbb;
504
}
505
506
static void checkBufferPositionAligned(ByteBuffer bb,
507
int pos, int alignment)
508
throws IOException
509
{
510
if (bb.alignmentOffset(pos, alignment) != 0) {
511
throw new IOException("Current location of the bytebuffer ("
512
+ pos + ") is not a multiple of the block size ("
513
+ alignment + ")");
514
}
515
}
516
517
static void checkRemainingBufferSizeAligned(int rem,
518
int alignment)
519
throws IOException
520
{
521
if (rem % alignment != 0) {
522
throw new IOException("Number of remaining bytes ("
523
+ rem + ") is not a multiple of the block size ("
524
+ alignment + ")");
525
}
526
}
527
528
static void checkChannelPositionAligned(long position,
529
int alignment)
530
throws IOException
531
{
532
if (position % alignment != 0) {
533
throw new IOException("Channel position (" + position
534
+ ") is not a multiple of the block size ("
535
+ alignment + ")");
536
}
537
}
538
}
539
540