Skip to content

Commit 77ec2a8

Browse files
committed
make recv_into work directly on the underlying byte[] of PByteArray if possible
1 parent df34fa5 commit 77ec2a8

File tree

2 files changed

+53
-20
lines changed

2 files changed

+53
-20
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/socket/SocketBuiltins.java

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.net.SocketAddress;
4747
import java.net.SocketException;
4848
import java.nio.ByteBuffer;
49+
import java.nio.channels.NotYetConnectedException;
4950
import java.nio.channels.ServerSocketChannel;
5051
import java.nio.channels.SocketChannel;
5152
import java.util.Arrays;
@@ -61,17 +62,22 @@
6162
import com.oracle.graal.python.builtins.objects.bytes.PBytes;
6263
import com.oracle.graal.python.builtins.objects.bytes.PIBytesLike;
6364
import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes;
65+
import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
6466
import com.oracle.graal.python.builtins.objects.tuple.PTuple;
6567
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
6668
import com.oracle.graal.python.nodes.function.PythonBuiltinNode;
6769
import com.oracle.graal.python.nodes.function.builtins.PythonBinaryBuiltinNode;
6870
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
6971
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
72+
import com.oracle.graal.python.runtime.sequence.storage.ByteSequenceStorage;
73+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
7074
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
7175
import com.oracle.truffle.api.dsl.Cached;
7276
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
7377
import com.oracle.truffle.api.dsl.NodeFactory;
7478
import com.oracle.truffle.api.dsl.Specialization;
79+
import com.oracle.truffle.api.frame.VirtualFrame;
80+
import com.oracle.truffle.api.profiles.ConditionProfile;
7581

7682
@CoreFunctions(extendClasses = PythonBuiltinClassType.PSocket)
7783
@SuppressWarnings("unused")
@@ -351,30 +357,49 @@ Object recvFrom(PSocket socket, int bufsize, PNone flags) {
351357
// recv_into(bufsize[, flags])
352358
@Builtin(name = "recv_into", minNumOfPositionalArgs = 1, maxNumOfPositionalArgs = 3)
353359
@GenerateNodeFactory
354-
abstract static class RecvIntoNode extends PythonBuiltinNode {
355-
@Specialization
356-
@TruffleBoundary
357-
Object recvInto(PSocket socket, PByteArray buffer) {
358-
byte[] targetBuffer = new byte[buffer.getSequenceStorage().length()];
359-
360-
int length = fillBuffer(socket, targetBuffer);
361-
// TODO: seems dirty, is there a better way to fill a byte array?
362-
363-
for (int i = 0; i < length; i++) {
364-
buffer.getSequenceStorage().insertItem(i, targetBuffer[i]);
360+
abstract static class RecvIntoNode extends PythonTernaryBuiltinNode {
361+
@Specialization
362+
Object recvInto(VirtualFrame frame, PSocket socket, PByteArray buffer, Object flags,
363+
@Cached ConditionProfile byteStorage,
364+
@Cached SequenceStorageNodes.LenNode lenNode,
365+
@Cached SequenceStorageNodes.SetItemNode setItem) {
366+
SequenceStorage storage = buffer.getSequenceStorage();
367+
int bufferLen = lenNode.execute(storage);
368+
if (byteStorage.profile(storage instanceof ByteSequenceStorage)) {
369+
ByteBuffer byteBuffer = ((ByteSequenceStorage) storage).getBufferView();
370+
try {
371+
return fillBuffer(socket, byteBuffer);
372+
} catch (NotYetConnectedException e) {
373+
throw raiseOSError(frame, OSErrorEnum.ENOTCONN, e);
374+
} catch (IOException e) {
375+
throw raiseOSError(frame, OSErrorEnum.EBADF, e);
376+
}
377+
} else {
378+
byte[] targetBuffer = new byte[bufferLen];
379+
ByteBuffer byteBuffer = ByteBuffer.wrap(targetBuffer);
380+
int length;
381+
try {
382+
length = fillBuffer(socket, byteBuffer);
383+
} catch (NotYetConnectedException e) {
384+
throw raiseOSError(frame, OSErrorEnum.ENOTCONN, e);
385+
} catch (IOException e) {
386+
throw raiseOSError(frame, OSErrorEnum.EBADF, e);
387+
}
388+
SequenceStorage newStorage = storage;
389+
for (int i = 0; i < length; i++) {
390+
newStorage = setItem.execute(newStorage, i, targetBuffer[i]);
391+
}
392+
if (newStorage != storage) {
393+
buffer.setSequenceStorage(newStorage);
394+
}
395+
return length;
365396
}
366-
367-
return length;
368397
}
369398

370-
int fillBuffer(PSocket socket, byte[] buffer) {
371-
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
399+
@TruffleBoundary
400+
private static int fillBuffer(PSocket socket, ByteBuffer byteBuffer) throws IOException {
372401
SocketChannel nativeSocket = socket.getSocket();
373-
try {
374-
return nativeSocket.read(byteBuffer);
375-
} catch (IOException e) {
376-
throw raise(PythonBuiltinClassType.OSError);
377-
}
402+
return nativeSocket.read(byteBuffer);
378403
}
379404
}
380405

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/sequence/storage/ByteSequenceStorage.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import static com.oracle.graal.python.runtime.exception.PythonErrorType.TypeError;
2929
import static com.oracle.graal.python.runtime.exception.PythonErrorType.ValueError;
3030

31+
import java.nio.ByteBuffer;
3132
import java.util.Arrays;
3233

3334
import com.oracle.graal.python.PythonLanguage;
@@ -99,6 +100,13 @@ public byte[] getInternalByteArray() {
99100
return values;
100101
}
101102

103+
@TruffleBoundary(allowInlining = true, transferToInterpreterOnException = false)
104+
public ByteBuffer getBufferView() {
105+
ByteBuffer view = ByteBuffer.wrap(values);
106+
view.limit(values.length);
107+
return view;
108+
}
109+
102110
@Override
103111
public Object getItemNormalized(int idx) {
104112
return getIntItemNormalized(idx);

0 commit comments

Comments
 (0)