Skip to content

Commit

Permalink
Automatically convert byte buffers to host byte arrays.
Browse files Browse the repository at this point in the history
  • Loading branch information
jchalou committed Sep 11, 2024
1 parent fe84b5f commit 9d3df24
Show file tree
Hide file tree
Showing 13 changed files with 505 additions and 93 deletions.
1 change: 1 addition & 0 deletions sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ This changelog summarizes major changes between GraalVM SDK versions. The main f

## Version 24.2.0
* GR-54905 When using Truffle NFI with the Panama backend, native access must now be granted to the Truffle module instead of the NFI Panama module. Use the `--enable-native-access=org.graalvm.truffle` Java command line option to enable the native access for the NFI Panama backend.
* GR-57681 Added the ability to use `Value#as(byte[].class)` to copy the contents of a guest language byte buffer (`Value#hasBufferElements()`) to a new byte array. The new functionality has precedence over accessing the guest object as array (`Value#hasArrayElements()`) if both ways are available.

## Version 24.1.0
* GR-51177 Enable random offsets of runtime compiled function entry points for the UNTRUSTED polyglot sandbox policy.
Expand Down
10 changes: 10 additions & 0 deletions sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Engine.java
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,16 @@ public byte byteSequenceByteAt(Object origin, int index) {
return ((ByteSequence) origin).byteAt(index);
}

@Override
public Object byteSequenceSubSequence(Object origin, int index, int length) {
return ((ByteSequence) origin).subSequence(index, index + length);
}

@Override
public byte[] byteSequenceToByteArray(Object origin) {
return ((ByteSequence) origin).toByteArray();
}

@Override
public boolean isInstrument(Object instrument) {
return instrument instanceof Instrument;
Expand Down
14 changes: 12 additions & 2 deletions sdk/src/org.graalvm.polyglot/src/org/graalvm/polyglot/Value.java
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@

import org.graalvm.polyglot.HostAccess.TargetMappingPrecedence;
import org.graalvm.polyglot.impl.AbstractPolyglotImpl.AbstractValueDispatch;
import org.graalvm.polyglot.io.ByteSequence;
import org.graalvm.polyglot.proxy.Proxy;

/**
Expand Down Expand Up @@ -489,7 +490,7 @@ public byte readBufferByte(long byteOffset) throws UnsupportedOperationException
* </pre>
*
* In case the goal is to read the whole contents into a single byte array, the easiest way is
* to do that through {@link org.graalvm.polyglot.io.ByteSequence}:
* to do that through {@link ByteSequence}:
*
* <pre>
* byte[] byteArray = val.as(ByteSequence.class).toByteArray();
Expand Down Expand Up @@ -1431,13 +1432,20 @@ public <T extends Proxy> T asProxyObject() {
* {@link HostAccess.MutableTargetMapping#ARRAY_TO_JAVA_LIST} is
* {@link HostAccess.Builder#allowMutableTargetMappings(HostAccess.MutableTargetMapping...)
* allowed} and the value has {@link #hasArrayElements() array elements} and it has an
* {@link Value#getArraySize() array size} that is smaller or equal than
* {@link Value#getArraySize() array size} that is smaller or equal to
* {@link Integer#MAX_VALUE}. The returned list can be safely cast to
* <code>List&lt;Object&gt;</code>. It is recommended to use {@link #as(TypeLiteral) type
* literals} to specify the expected component type. With type literals the value type can be
* restricted to any supported target type, for example to <code>List&lt;Integer&gt;</code>. If
* the raw <code>{@link List}.class</code> or an Object component type is used, then the return
* types of the the list are recursively subject to Object target type mapping rules.
* <li><code>{@link ByteSequence}.class</code> is supported if the value has
* {@link #hasBufferElements() buffer elements} and it has a {@link Value#getBufferSize() buffer
* size} that is smaller or equal to {@link Integer#MAX_VALUE}.
* <li><code>byte[].class</code> is supported if the value has {@link #hasBufferElements()
* buffer elements} and it has a {@link Value#getBufferSize() buffer size} that is smaller or
* equal to <code>{@link Integer#MAX_VALUE} - 8</code>. The contents of the buffer will be
* copied to a new byte array with appropriate size.
* <li>Any Java array type of a supported target type. The values of the value will be eagerly
* coerced and copied into a new instance of the provided array type. This means that changes in
* returned array will not be reflected in the original value. Since conversion to a Java array
Expand Down Expand Up @@ -1509,6 +1517,8 @@ public <T extends Proxy> T asProxyObject() {
* assert context.eval("js", "42").as(Integer.class) == 42;
* assert context.eval("js", "({foo:'bar'})").as(Map.class).get("foo").equals("bar");
* assert context.eval("js", "[42]").as(List.class).get(0).equals(42);
* assert Arrays.equals(context.eval("js", "([0, 1, 127])").as(byte[].class), new byte[]{0, 1, 127});
* assert Arrays.equals(context.eval("js", "(new Uint8Array([0, 1, 127, 255]))").getMember("buffer").as(byte[].class), new byte[]{0, 1, 127, -1});
* assert ((Map&lt;String, Object>) context.eval("js", "[{foo:'bar'}]").as(List.class).get(0)).get("foo").equals("bar");
*
* &#64;FunctionalInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,10 @@ protected APIAccess() {

public abstract byte byteSequenceByteAt(Object origin, int index);

public abstract Object byteSequenceSubSequence(Object origin, int index, int length);

public abstract byte[] byteSequenceToByteArray(Object origin);

public abstract boolean isProxyArray(Object proxy);

public abstract boolean isProxyDate(Object proxy);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
Expand Down Expand Up @@ -142,18 +142,16 @@ public int hashCode() {
}

public ByteSequence subSequence(int startIndex, int endIndex) {
int l = endIndex - startIndex;
if (l < 0) {
throw new IndexOutOfBoundsException(String.valueOf(l));
}
final int realStartIndex = start + startIndex;
if (realStartIndex < 0) {
if (startIndex < 0) {
throw new IndexOutOfBoundsException(String.valueOf(startIndex));
}
if (endIndex < startIndex) {
throw new IndexOutOfBoundsException(String.valueOf((long) endIndex - startIndex));
}
if (endIndex > length()) {
throw new IndexOutOfBoundsException(String.valueOf(realStartIndex + l));
throw new IndexOutOfBoundsException(String.valueOf(endIndex));
}
return new ByteArraySequence(buffer, realStartIndex, l);
return new ByteArraySequence(buffer, start + startIndex, endIndex - startIndex);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -257,5 +257,9 @@
{
"name": "com.oracle.truffle.api.test.polyglot.GuestFunctionToHostInterfaceProxyTest$HostCallee",
"allPublicMethods": true
},
{
"name": "java.nio.HeapByteBuffer",
"allPublicMethods": true
}
]
Loading

0 comments on commit 9d3df24

Please sign in to comment.