Skip to content

Commit ab15020

Browse files
committed
[GR-28203] ByteBuffer.duplicate() is not designed for PE.
1 parent ec427e5 commit ab15020

File tree

3 files changed

+249
-3
lines changed

3 files changed

+249
-3
lines changed
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/*
2+
* Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.truffle.js.runtime.array;
42+
43+
import java.lang.reflect.Field;
44+
import java.nio.Buffer;
45+
import java.nio.ByteBuffer;
46+
import java.nio.ByteOrder;
47+
48+
import com.oracle.truffle.api.CompilerDirectives;
49+
50+
import sun.misc.Unsafe;
51+
52+
final class ByteBufferSupport {
53+
private static final ByteBufferAccess LITTLE_ENDIAN;
54+
private static final ByteBufferAccess BIG_ENDIAN;
55+
private static final ByteBufferAccess NATIVE_ORDER;
56+
57+
private ByteBufferSupport() {
58+
}
59+
60+
static ByteBufferAccess littleEndian() {
61+
return LITTLE_ENDIAN;
62+
}
63+
64+
static ByteBufferAccess bigEndian() {
65+
return BIG_ENDIAN;
66+
}
67+
68+
static ByteBufferAccess nativeOrder() {
69+
return NATIVE_ORDER;
70+
}
71+
72+
static {
73+
// We only use Unsafe for architectures that we know support unaligned accesses.
74+
String arch = System.getProperty("os.arch");
75+
boolean unaligned = arch.equals("amd64") ||
76+
arch.equals("aarch64") ||
77+
arch.equals("x86_64");
78+
if (unaligned) {
79+
if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
80+
LITTLE_ENDIAN = NativeUnsafeByteBufferAccess.INSTANCE;
81+
BIG_ENDIAN = ReservedUnsafeByteBufferAccess.INSTANCE;
82+
} else {
83+
LITTLE_ENDIAN = ReservedUnsafeByteBufferAccess.INSTANCE;
84+
BIG_ENDIAN = NativeUnsafeByteBufferAccess.INSTANCE;
85+
}
86+
NATIVE_ORDER = NativeUnsafeByteBufferAccess.INSTANCE;
87+
} else {
88+
LITTLE_ENDIAN = LittleEndianByteBufferAccess.INSTANCE;
89+
BIG_ENDIAN = BigEndianByteBufferAccess.INSTANCE;
90+
NATIVE_ORDER = NativeByteBufferAccess.INSTANCE;
91+
}
92+
}
93+
}
94+
95+
abstract class UnsafeByteBufferAccess extends ByteBufferAccess {
96+
97+
private static final Unsafe UNSAFE;
98+
private static final long BUFFER_ADDRESS_FIELD_OFFSET;
99+
100+
private static int checkIndex(ByteBuffer buffer, int i, int nb) {
101+
if (nb < 1 || i < 0 || i > buffer.limit() - nb) {
102+
CompilerDirectives.transferToInterpreterAndInvalidate();
103+
throw new IndexOutOfBoundsException();
104+
}
105+
return i;
106+
}
107+
108+
private static long getBufferAddress(ByteBuffer buffer) {
109+
return UNSAFE.getLong(buffer, BUFFER_ADDRESS_FIELD_OFFSET);
110+
}
111+
112+
private static long getAddress(ByteBuffer buffer, int index) {
113+
return getBufferAddress(buffer) + index;
114+
}
115+
116+
@Override
117+
public int getInt16(ByteBuffer buffer, int index) {
118+
return UNSAFE.getShort(getAddress(buffer, checkIndex(buffer, index, Short.BYTES)));
119+
}
120+
121+
@Override
122+
public int getInt32(ByteBuffer buffer, int index) {
123+
return UNSAFE.getInt(getAddress(buffer, checkIndex(buffer, index, Integer.BYTES)));
124+
}
125+
126+
@Override
127+
public long getInt64(ByteBuffer buffer, int index) {
128+
return UNSAFE.getLong(getAddress(buffer, checkIndex(buffer, index, Long.BYTES)));
129+
}
130+
131+
@Override
132+
public float getFloat(ByteBuffer buffer, int index) {
133+
return UNSAFE.getFloat(getAddress(buffer, checkIndex(buffer, index, Float.BYTES)));
134+
}
135+
136+
@Override
137+
public double getDouble(ByteBuffer buffer, int index) {
138+
return UNSAFE.getDouble(getAddress(buffer, checkIndex(buffer, index, Double.BYTES)));
139+
}
140+
141+
@Override
142+
public void putInt16(ByteBuffer buffer, int index, int value) {
143+
UNSAFE.putShort(getAddress(buffer, checkIndex(buffer, index, Short.BYTES)), (short) value);
144+
}
145+
146+
@Override
147+
public void putInt32(ByteBuffer buffer, int index, int value) {
148+
UNSAFE.putInt(getAddress(buffer, checkIndex(buffer, index, Integer.BYTES)), value);
149+
}
150+
151+
@Override
152+
public void putInt64(ByteBuffer buffer, int index, long value) {
153+
UNSAFE.putLong(getAddress(buffer, checkIndex(buffer, index, Long.BYTES)), value);
154+
}
155+
156+
@Override
157+
public void putFloat(ByteBuffer buffer, int index, float value) {
158+
UNSAFE.putFloat(getAddress(buffer, checkIndex(buffer, index, Float.BYTES)), value);
159+
}
160+
161+
@Override
162+
public void putDouble(ByteBuffer buffer, int index, double value) {
163+
UNSAFE.putDouble(getAddress(buffer, checkIndex(buffer, index, Double.BYTES)), value);
164+
}
165+
166+
static {
167+
try {
168+
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
169+
theUnsafeInstance.setAccessible(true);
170+
UNSAFE = (Unsafe) theUnsafeInstance.get(Unsafe.class);
171+
} catch (NoSuchFieldException | IllegalAccessException e) {
172+
throw new RuntimeException("exception while trying to get Unsafe.theUnsafe via reflection:", e);
173+
}
174+
try {
175+
Field bufferAddressField = Buffer.class.getDeclaredField("address");
176+
BUFFER_ADDRESS_FIELD_OFFSET = UNSAFE.objectFieldOffset(bufferAddressField);
177+
} catch (NoSuchFieldException e) {
178+
throw new RuntimeException(e);
179+
}
180+
}
181+
}
182+
183+
final class NativeUnsafeByteBufferAccess extends UnsafeByteBufferAccess {
184+
static final ByteBufferAccess INSTANCE = new NativeUnsafeByteBufferAccess();
185+
}
186+
187+
final class ReservedUnsafeByteBufferAccess extends UnsafeByteBufferAccess {
188+
static final ByteBufferAccess INSTANCE = new ReservedUnsafeByteBufferAccess();
189+
190+
@Override
191+
public int getInt16(ByteBuffer buffer, int index) {
192+
return Short.reverseBytes((short) super.getInt16(buffer, index));
193+
}
194+
195+
@Override
196+
public int getInt32(ByteBuffer buffer, int index) {
197+
return Integer.reverseBytes(super.getInt32(buffer, index));
198+
}
199+
200+
@Override
201+
public long getInt64(ByteBuffer buffer, int index) {
202+
return Long.reverseBytes(super.getInt64(buffer, index));
203+
}
204+
205+
@Override
206+
public float getFloat(ByteBuffer buffer, int index) {
207+
return Float.intBitsToFloat(getInt32(buffer, index));
208+
}
209+
210+
@Override
211+
public double getDouble(ByteBuffer buffer, int index) {
212+
return Double.longBitsToDouble(getInt64(buffer, index));
213+
}
214+
215+
@Override
216+
public void putInt16(ByteBuffer buffer, int index, int value) {
217+
super.putInt16(buffer, index, Short.reverseBytes((short) value));
218+
}
219+
220+
@Override
221+
public void putInt32(ByteBuffer buffer, int index, int value) {
222+
super.putInt32(buffer, index, Integer.reverseBytes(value));
223+
}
224+
225+
@Override
226+
public void putInt64(ByteBuffer buffer, int index, long value) {
227+
super.putInt64(buffer, index, Long.reverseBytes(value));
228+
}
229+
230+
@Override
231+
public void putFloat(ByteBuffer buffer, int index, float value) {
232+
putInt32(buffer, index, Float.floatToRawIntBits(value));
233+
}
234+
235+
@Override
236+
public void putDouble(ByteBuffer buffer, int index, double value) {
237+
putInt64(buffer, index, Double.doubleToRawLongBits(value));
238+
}
239+
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Boundaries.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,4 +402,9 @@ public static ByteBuffer byteBufferSlice(ByteBuffer buf, int pos, int limit) {
402402
BufferUtil.asBaseBuffer(dup).position(pos).limit(limit);
403403
return dup.slice();
404404
}
405+
406+
@TruffleBoundary(allowInlining = true)
407+
public static ByteBuffer byteBufferDuplicate(ByteBuffer buffer) {
408+
return buffer.duplicate();
409+
}
405410
}

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/ByteBufferAccess.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343
import java.nio.ByteBuffer;
4444
import java.nio.ByteOrder;
4545

46+
import com.oracle.truffle.js.runtime.Boundaries;
47+
4648
abstract class ByteBufferAccess {
4749

4850
@SuppressWarnings("static-method")
@@ -166,7 +168,7 @@ final class NativeByteBufferAccess extends AbstractByteBufferAccess {
166168

167169
@Override
168170
protected ByteBuffer wrap(ByteBuffer buffer) {
169-
return buffer.duplicate().order(ByteOrder.nativeOrder());
171+
return Boundaries.byteBufferDuplicate(buffer).order(ByteOrder.nativeOrder());
170172
}
171173
}
172174

@@ -175,7 +177,7 @@ final class LittleEndianByteBufferAccess extends AbstractByteBufferAccess {
175177

176178
@Override
177179
protected ByteBuffer wrap(ByteBuffer buffer) {
178-
return buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
180+
return Boundaries.byteBufferDuplicate(buffer).order(ByteOrder.LITTLE_ENDIAN);
179181
}
180182
}
181183

@@ -184,6 +186,6 @@ final class BigEndianByteBufferAccess extends AbstractByteBufferAccess {
184186

185187
@Override
186188
protected ByteBuffer wrap(ByteBuffer buffer) {
187-
return buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
189+
return Boundaries.byteBufferDuplicate(buffer).order(ByteOrder.BIG_ENDIAN);
188190
}
189191
}

0 commit comments

Comments
 (0)