Skip to content

Commit d55161c

Browse files
committed
[GR-50795] Adopt new InteropLibrary#readBuffer message.
PullRequest: js/3003
2 parents 34f7ea8 + eaf0116 commit d55161c

File tree

14 files changed

+176
-89
lines changed

14 files changed

+176
-89
lines changed

graal-js/src/com.oracle.truffle.js.codec/src/com/oracle/truffle/js/codec/BinaryDecoder.java

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -40,6 +40,8 @@
4040
*/
4141
package com.oracle.truffle.js.codec;
4242

43+
import java.lang.invoke.MethodHandles;
44+
import java.lang.invoke.VarHandle;
4345
import java.math.BigInteger;
4446
import java.nio.ByteBuffer;
4547
import java.nio.ByteOrder;
@@ -49,16 +51,27 @@
4951
/**
5052
* Utility for decoding values from a ByteBuffer.
5153
*/
52-
public class BinaryDecoder {
54+
public final class BinaryDecoder {
5355

54-
private ByteBuffer buffer;
56+
private static final VarHandle INT32 = MethodHandles.byteBufferViewVarHandle(int[].class, ByteOrder.LITTLE_ENDIAN);
57+
private static final VarHandle INT64 = MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.LITTLE_ENDIAN);
58+
59+
private final ByteBuffer buffer;
60+
private int pos;
61+
62+
public BinaryDecoder(ByteBuffer buffer, int position) {
63+
this.buffer = buffer;
64+
this.pos = position;
65+
}
5566

5667
public BinaryDecoder(ByteBuffer buffer) {
57-
this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN);
68+
this(buffer, 0);
5869
}
5970

6071
private int getU1() {
61-
return Byte.toUnsignedInt(buffer.get());
72+
int u1 = Byte.toUnsignedInt(buffer.get(pos));
73+
pos += Byte.BYTES;
74+
return u1;
6275
}
6376

6477
/**
@@ -152,25 +165,15 @@ public double getDouble() {
152165
}
153166

154167
public long getInt64() {
155-
long result = 0;
156-
int shift = 0;
157-
for (int i = 0; i < Long.BYTES; i++) {
158-
long b = getU1();
159-
result |= b << shift;
160-
shift += 8;
161-
}
162-
return result;
168+
long i64 = (long) INT64.get(buffer, pos);
169+
pos += Long.BYTES;
170+
return i64;
163171
}
164172

165173
public int getInt32() {
166-
int result = 0;
167-
int shift = 0;
168-
for (int i = 0; i < Integer.BYTES; i++) {
169-
long b = getU1();
170-
result |= b << shift;
171-
shift += 8;
172-
}
173-
return result;
174+
int i32 = (int) INT32.get(buffer, pos);
175+
pos += Integer.BYTES;
176+
return i32;
174177
}
175178

176179
public boolean hasRemaining() {

graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/JSTest.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,27 @@ public static void assertTStringEquals(String a, Object b) {
8989
}
9090

9191
public static void assertThrows(Runnable test, Consumer<PolyglotException> exceptionVerifier) {
92+
assertThrows(test, PolyglotException.class, exceptionVerifier);
93+
}
94+
95+
public static <T extends Throwable> void assertThrows(Runnable test, Class<T> exceptionType, Consumer<T> exceptionVerifier) {
9296
try {
9397
test.run();
94-
fail("should have thrown");
95-
} catch (PolyglotException e) {
96-
exceptionVerifier.accept(e);
98+
fail("should have thrown " + exceptionType.getSimpleName());
99+
} catch (Throwable e) {
100+
if (exceptionType.isInstance(e)) {
101+
exceptionVerifier.accept(exceptionType.cast(e));
102+
} else {
103+
throw e;
104+
}
97105
}
98106
}
99107

108+
public static <T extends Throwable> void assertThrows(Runnable test, Class<T> exceptionType) {
109+
assertThrows(test, exceptionType, (T e) -> {
110+
});
111+
}
112+
100113
public static void assertThrows(Runnable test, JSErrorType expectedJSError) {
101114
try {
102115
test.run();

graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/InteropByteBufferTest.java

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID;
4444
import static com.oracle.truffle.js.test.JSTest.assertThrows;
45+
import static org.junit.Assert.assertArrayEquals;
4546
import static org.junit.Assert.assertEquals;
4647
import static org.junit.Assert.assertTrue;
4748

@@ -185,19 +186,20 @@ public void testArrayBufferInteropHeap() {
185186

186187
private static void testArrayBufferInteropCommon(boolean direct) {
187188
try (Context cx = JSTest.newContextBuilder().option(JSContextOptions.DIRECT_BYTE_BUFFER_NAME, Boolean.toString(direct)).build()) {
188-
Value buffer = cx.eval("js", "" +
189-
"const ab = new ArrayBuffer(25);" +
190-
"let ia = new Int8Array(ab);" +
191-
"ia[0] = 41;" +
192-
"ia[1] = 42;" +
193-
"ia[2] = 43;" +
194-
"ia[3] = 44;" +
195-
"ia = new Int32Array(ab, 4, 2);" +
196-
"ia[0] = 45;" +
197-
"ia[1] = 46;" +
198-
"ia = new BigInt64Array(ab, 16, 1);" +
199-
"ia[0] = 2n ** 63n - 43n;" +
200-
"ab;");
189+
Value buffer = cx.eval("js", """
190+
const ab = new ArrayBuffer(25);
191+
let ia = new Int8Array(ab);
192+
ia[0] = 41;
193+
ia[1] = 42;
194+
ia[2] = 43;
195+
ia[3] = 44;
196+
ia = new Int32Array(ab, 4, 2);
197+
ia[0] = 45;
198+
ia[1] = 46;
199+
ia = new BigInt64Array(ab, 16, 1);
200+
ia[0] = 2n ** 63n - 43n;
201+
ab;
202+
""");
201203
assertEquals(25, buffer.getBufferSize());
202204
assertEquals(buffer.readBufferByte(0), 41);
203205
assertEquals(buffer.readBufferByte(1), 42);
@@ -218,6 +220,16 @@ private static void testArrayBufferInteropCommon(boolean direct) {
218220
assertTrue(buffer.isBufferWritable());
219221
buffer.writeBufferLong(ByteOrder.nativeOrder(), 16, Double.doubleToRawLongBits(Double.NEGATIVE_INFINITY));
220222
assertEquals(buffer.readBufferDouble(ByteOrder.nativeOrder(), 16), Double.NEGATIVE_INFINITY, 0.0);
223+
224+
byte[] dst = new byte[4];
225+
buffer.readBuffer(0, dst, 0, 4);
226+
assertArrayEquals(new byte[]{41, 42, 43, 44}, dst);
227+
buffer.readBuffer(3, dst, 2, 2);
228+
assertArrayEquals(new byte[]{41, 42, 44, (byte) (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? 45 : 0)}, dst);
229+
230+
assertThrows(() -> buffer.readBuffer(-1, new byte[4], 0, 0), IndexOutOfBoundsException.class);
231+
assertThrows(() -> buffer.readBuffer(0, new byte[24], 0, 25), IndexOutOfBoundsException.class);
232+
assertThrows(() -> buffer.readBuffer(1, new byte[25], 0, 25), IndexOutOfBoundsException.class);
221233
}
222234
}
223235

@@ -233,15 +245,14 @@ private static void testDataViewBackedByHostByteBuffer(boolean direct, boolean v
233245
ByteBuffer buffer = direct ? ByteBuffer.allocateDirect(32) : ByteBuffer.allocate(32);
234246
try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.newBuilder().allowBufferAccess(true).build()).build()) {
235247
context.getBindings(ID).putMember("bb", buffer);
236-
Value dataView = context.eval(ID, "" +
237-
"const ab = " + (viaArrayBuffer ? "new ArrayBuffer(bb)" : "bb") + ";" +
238-
"let dv = new DataView(ab);" +
239-
"dv;");
240-
context.eval(ID, "" +
241-
"dv.setInt8(0, 41);" +
242-
"dv.setInt8(1, dv.getInt8(0) + 1);" +
243-
"dv.setUint8(2, dv.getUint8(1) + 1);" +
244-
"dv.setInt32(3, -44, true);");
248+
Value arrayBuffer = context.eval(ID, "const ab = " + (viaArrayBuffer ? "new ArrayBuffer(bb)" : "bb") + "; ab;");
249+
Value dataView = context.eval(ID, "let dv = new DataView(ab); dv;");
250+
context.eval(ID, """
251+
dv.setInt8(0, 41);
252+
dv.setInt8(1, dv.getInt8(0) + 1);
253+
dv.setUint8(2, dv.getUint8(1) + 1);
254+
dv.setInt32(3, -44, true);
255+
""");
245256
assertEquals(41, buffer.get(0));
246257
assertEquals(42, buffer.get(1));
247258
assertEquals(43, buffer.get(2));
@@ -265,6 +276,16 @@ private static void testDataViewBackedByHostByteBuffer(boolean direct, boolean v
265276
context.eval(ID, "dv.setBigInt64(24, 1742123762643437888n, false);");
266277
assertEquals(4614256656552045848L, dataView.invokeMember("getBigInt64", 24, true).asLong());
267278
assertEquals(Math.PI, dataView.invokeMember("getFloat64", 24, true).asDouble(), 0.0);
279+
280+
byte[] dst = new byte[4];
281+
arrayBuffer.readBuffer(0, dst, 0, 4);
282+
assertArrayEquals(new byte[]{41, 42, 43, 44}, dst);
283+
arrayBuffer.readBuffer(2, dst, 1, 3);
284+
assertArrayEquals(new byte[]{41, 43, 44, -1}, dst);
285+
286+
assertThrows(() -> arrayBuffer.readBuffer(-1, new byte[4], 0, 0), IndexOutOfBoundsException.class);
287+
assertThrows(() -> arrayBuffer.readBuffer(0, new byte[31], 0, 32), IndexOutOfBoundsException.class);
288+
assertThrows(() -> arrayBuffer.readBuffer(1, new byte[33], 0, 32), IndexOutOfBoundsException.class);
268289
}
269290
}
270291

@@ -287,11 +308,19 @@ public void testDetachedInteropArrayBuffer() {
287308
try (Context context = JSTest.newContextBuilder().allowHostAccess(hostAccess).allowExperimentalOptions(true).option("js.debug-builtin", "true").option("js.v8-compat", "true").build()) {
288309
ByteBuffer buffer = ByteBuffer.wrap(new byte[]{1, 2, 3});
289310
context.getBindings("js").putMember("buffer", buffer);
290-
Value byteLength = context.eval(ID, "" +
291-
"var arrayBuffer = new ArrayBuffer(buffer);\n" +
292-
"Debug.typedArrayDetachBuffer(arrayBuffer);\n" +
293-
"arrayBuffer.byteLength;");
311+
Value byteLength = context.eval(ID, """
312+
var arrayBuffer = new ArrayBuffer(buffer);
313+
Debug.typedArrayDetachBuffer(arrayBuffer);
314+
arrayBuffer.byteLength;
315+
""");
294316
assertEquals(0, byteLength.asInt());
317+
318+
Value arrayBuffer = context.getBindings(ID).getMember("arrayBuffer");
319+
assertTrue(arrayBuffer.hasBufferElements());
320+
assertThrows(() -> arrayBuffer.readBuffer(0, new byte[1], 0, 1), IndexOutOfBoundsException.class);
321+
322+
// even reading zero bytes is not allowed for detached buffers
323+
assertThrows(() -> arrayBuffer.readBuffer(0, new byte[0], 0, 0), IndexOutOfBoundsException.class);
295324
}
296325
}
297326

graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JSNodeDecoder.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,8 @@ public Object decodeNode(NodeDecoder.DecoderState state, NodeFactory nodeFactory
301301
System.err.println("callex pos:" + position);
302302
}
303303
final Object[] arguments = getObjectArray(state);
304-
final ByteBuffer buffer = state.getBuffer().duplicate().position(position);
305-
NodeDecoder.DecoderState extracted = new NodeDecoder.DecoderState(new BinaryDecoder(buffer), arguments);
304+
final ByteBuffer buffer = state.getBuffer();
305+
NodeDecoder.DecoderState extracted = new NodeDecoder.DecoderState(new BinaryDecoder(buffer, position), arguments);
306306
storeResult(state, decodeNode(extracted, nodeFactory, context, source));
307307
break;
308308
}
@@ -314,7 +314,7 @@ public Object decodeNode(NodeDecoder.DecoderState state, NodeFactory nodeFactory
314314
}
315315
JSFunctionData functionData = (JSFunctionData) state.getObject();
316316
final Object[] arguments = getObjectArray(state);
317-
final ByteBuffer buffer = state.getBuffer().duplicate().position(position);
317+
final ByteBuffer buffer = state.getBuffer();
318318
functionData.setLazyInit(new JSFunctionData.Initializer() {
319319
@Override
320320
public void initializeRoot(JSFunctionData fd) {
@@ -323,7 +323,7 @@ public void initializeRoot(JSFunctionData fd) {
323323
if (VERBOSE) {
324324
System.out.println("Decoding: " + fd.getName());
325325
}
326-
NodeDecoder.DecoderState extracted = new NodeDecoder.DecoderState(new BinaryDecoder(buffer), arguments);
326+
NodeDecoder.DecoderState extracted = new NodeDecoder.DecoderState(new BinaryDecoder(buffer, position), arguments);
327327
decodeNode(extracted, nodeFactory, context, source);
328328
fd.releaseLazyInit();
329329
}

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

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -230,29 +230,22 @@ public static byte[] byteBufferArray(ByteBuffer buffer) {
230230

231231
@TruffleBoundary(allowInlining = true)
232232
public static void byteBufferPutSlice(ByteBuffer dst, int dstPos, ByteBuffer src, int srcPos, int srcLimit) {
233-
ByteBuffer slice = byteBufferSlice(src, srcPos, srcLimit);
234-
ByteBuffer dstDup = dst.duplicate();
235-
dstDup.position(dstPos);
236-
dstDup.put(slice);
233+
dst.put(dstPos, src, srcPos, srcLimit - srcPos);
237234
}
238235

239236
@TruffleBoundary(allowInlining = true)
240237
public static ByteBuffer byteBufferSlice(ByteBuffer buf, int pos, int limit) {
241-
ByteBuffer dup = buf.duplicate();
242-
dup.position(pos).limit(limit);
243-
return dup.slice();
238+
return buf.slice(pos, limit - pos);
244239
}
245240

246241
@TruffleBoundary(allowInlining = true)
247-
public static ByteBuffer byteBufferDuplicate(ByteBuffer buffer) {
248-
return buffer.duplicate();
242+
public static void byteBufferGet(ByteBuffer src, int srcPos, byte[] dst, int dstPos, int length) {
243+
src.get(srcPos, dst, dstPos, length);
249244
}
250245

251246
@TruffleBoundary(allowInlining = true)
252247
public static void byteBufferPutArray(ByteBuffer dst, int dstPos, byte[] src, int srcPos, int srcLength) {
253-
ByteBuffer dstDup = dst.duplicate();
254-
dstDup.position(dstPos);
255-
dstDup.put(src, srcPos, srcLength);
248+
dst.put(dstPos, src, srcPos, srcLength);
256249
}
257250

258251
@TruffleBoundary

0 commit comments

Comments
 (0)