Skip to content

Commit 0a17b6a

Browse files
committed
Implement wrapper to expose bytes-like object as Java byte[]
1 parent b510758 commit 0a17b6a

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/JavaModuleBuiltins.java

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5252
import com.oracle.graal.python.builtins.PythonBuiltins;
5353
import com.oracle.graal.python.builtins.objects.PNone;
54+
import com.oracle.graal.python.builtins.objects.bytes.PBytesLike;
5455
import com.oracle.graal.python.builtins.objects.module.PythonModule;
5556
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
5657
import com.oracle.graal.python.builtins.objects.str.PString;
@@ -63,6 +64,7 @@
6364
import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
6465
import com.oracle.graal.python.runtime.PythonCore;
6566
import com.oracle.graal.python.runtime.exception.PythonErrorType;
67+
import com.oracle.graal.python.runtime.interop.InteropByteArray;
6668
import com.oracle.truffle.api.CompilerDirectives;
6769
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
6870
import com.oracle.truffle.api.TruffleLanguage.Env;
@@ -72,8 +74,13 @@
7274
import com.oracle.truffle.api.dsl.NodeFactory;
7375
import com.oracle.truffle.api.dsl.Specialization;
7476
import com.oracle.truffle.api.frame.VirtualFrame;
77+
import com.oracle.truffle.api.interop.InteropLibrary;
78+
import com.oracle.truffle.api.interop.InvalidArrayIndexException;
7579
import com.oracle.truffle.api.interop.TruffleObject;
80+
import com.oracle.truffle.api.interop.UnsupportedMessageException;
7681
import com.oracle.truffle.api.library.CachedLibrary;
82+
import com.oracle.truffle.api.library.ExportLibrary;
83+
import com.oracle.truffle.api.library.ExportMessage;
7784

7885
@CoreFunctions(defineModule = JavaModuleBuiltins.JAVA)
7986
public class JavaModuleBuiltins extends PythonBuiltins {
@@ -259,4 +266,92 @@ Object none(VirtualFrame frame, PythonModule mod, Object name,
259266
return lib.callObject(getAttr(frame, mod, lib), frame, name);
260267
}
261268
}
269+
270+
@Builtin(name = "as_java_byte_array", minNumOfPositionalArgs = 1)
271+
@GenerateNodeFactory
272+
abstract static class AsJavaByteArrayNode extends PythonUnaryBuiltinNode {
273+
@Specialization
274+
static Object doBytesByteStorage(PBytesLike object) {
275+
return new PUnsignedBytesWrapper(object);
276+
}
277+
278+
@Specialization(guards = "lib.isBuffer(object)", limit = "3")
279+
static Object doBuffer(Object object,
280+
@CachedLibrary("object") PythonObjectLibrary lib) {
281+
try {
282+
return new InteropByteArray(lib.getBufferBytes(object));
283+
} catch (UnsupportedMessageException e) {
284+
throw CompilerDirectives.shouldNotReachHere();
285+
}
286+
}
287+
288+
@Fallback
289+
Object doError(Object object) {
290+
throw raise(PythonBuiltinClassType.TypeError, ErrorMessages.BYTESLIKE_OBJ_REQUIRED, object);
291+
}
292+
}
293+
294+
/**
295+
* A simple wrapper object that bit-casts an integer in range {@code 0-255} to a Java
296+
* {@code byte}. This can be used to expose a bytes-like object to Java as {@code byte[]}.
297+
*/
298+
@ExportLibrary(value = InteropLibrary.class, delegateTo = "delegate")
299+
@SuppressWarnings("static-method")
300+
static final class PUnsignedBytesWrapper implements TruffleObject {
301+
final PBytesLike delegate;
302+
303+
PUnsignedBytesWrapper(PBytesLike delegate) {
304+
this.delegate = delegate;
305+
}
306+
307+
@ExportMessage
308+
boolean hasArrayElements(
309+
@CachedLibrary("this.delegate") InteropLibrary delegateLib) {
310+
return delegateLib.hasArrayElements(delegate);
311+
}
312+
313+
@ExportMessage
314+
boolean isArrayElementReadable(long index,
315+
@CachedLibrary("this.delegate") InteropLibrary delegateLib) {
316+
return delegateLib.isArrayElementReadable(delegate, index);
317+
}
318+
319+
@ExportMessage
320+
long getArraySize(
321+
@CachedLibrary("this.delegate") InteropLibrary delegateLib) throws UnsupportedMessageException {
322+
return delegateLib.getArraySize(delegate);
323+
}
324+
325+
@ExportMessage
326+
Object readArrayElement(long index,
327+
@CachedLibrary("this.delegate") InteropLibrary delegateLib,
328+
@CachedLibrary(limit = "1") InteropLibrary elementLib) throws InvalidArrayIndexException, UnsupportedMessageException {
329+
Object element = delegateLib.readArrayElement(delegate, index);
330+
if (elementLib.fitsInLong(element)) {
331+
long i = elementLib.asLong(element);
332+
if (compareUnsigned(i, Byte.MAX_VALUE) <= 0) {
333+
return (byte) i;
334+
} else if (compareUnsigned(i, 0xFF) <= 0) {
335+
return (byte) -(-i & 0xFF);
336+
}
337+
}
338+
throw CompilerDirectives.shouldNotReachHere("bytes object contains non-byte values");
339+
}
340+
341+
/**
342+
* This is taken from {@link Long#compare(long, long)}} (just to avoid a
343+
* {@code TruffleBoundary}).
344+
*/
345+
private static int compare(long x, long y) {
346+
return (x < y) ? -1 : ((x == y) ? 0 : 1);
347+
}
348+
349+
/**
350+
* This is taken from {@link Long#compareUnsigned(long, long)}} (just to avoid a
351+
* {@code TruffleBoundary}).
352+
*/
353+
private static int compareUnsigned(long x, long y) {
354+
return compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
355+
}
356+
}
262357
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 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.graal.python.runtime.interop;
42+
43+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
44+
import com.oracle.truffle.api.interop.InteropLibrary;
45+
import com.oracle.truffle.api.interop.TruffleObject;
46+
import com.oracle.truffle.api.library.ExportLibrary;
47+
import com.oracle.truffle.api.library.ExportMessage;
48+
49+
@ExportLibrary(InteropLibrary.class)
50+
@SuppressWarnings("static-method")
51+
public final class InteropByteArray implements TruffleObject {
52+
@CompilationFinal(dimensions = 1) private final byte[] array;
53+
54+
public InteropByteArray(byte[] array) {
55+
this.array = array;
56+
}
57+
58+
@ExportMessage
59+
Object readArrayElement(long idx) {
60+
return array[(int) idx];
61+
}
62+
63+
@ExportMessage
64+
long getArraySize() {
65+
return array.length;
66+
}
67+
68+
@ExportMessage
69+
boolean hasArrayElements() {
70+
return true;
71+
}
72+
73+
@ExportMessage
74+
boolean isArrayElementReadable(long idx) {
75+
return idx < array.length;
76+
}
77+
}

0 commit comments

Comments
 (0)