Skip to content

Commit a379d53

Browse files
committed
Inline MemoryBIO into PMemoryBIO
1 parent c823115 commit a379d53

File tree

7 files changed

+158
-211
lines changed

7 files changed

+158
-211
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/MemoryBIO.java

Lines changed: 0 additions & 169 deletions
This file was deleted.

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/MemoryBIOBuiltins.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ PMemoryBIO create(Object type) {
9090
abstract static class PendingNode extends PythonUnaryBuiltinNode {
9191
@Specialization
9292
static int getPending(PMemoryBIO self) {
93-
return self.getBio().getPending();
93+
return self.getPending();
9494
}
9595
}
9696

@@ -99,7 +99,7 @@ static int getPending(PMemoryBIO self) {
9999
abstract static class EOFNode extends PythonUnaryBuiltinNode {
100100
@Specialization
101101
static boolean eof(PMemoryBIO self) {
102-
return self.getBio().isEOF();
102+
return self.isEOF();
103103
}
104104
}
105105

@@ -110,7 +110,7 @@ abstract static class ReadNode extends PythonBinaryClinicBuiltinNode {
110110
@Specialization
111111
PBytes read(PMemoryBIO self, int size) {
112112
int len = size >= 0 ? size : Integer.MAX_VALUE;
113-
return factory().createBytes(self.getBio().read(len));
113+
return factory().createBytes(self.read(len));
114114
}
115115

116116
@Override
@@ -125,13 +125,13 @@ abstract static class WriteNode extends PythonBinaryBuiltinNode {
125125
@Specialization(guards = "lib.isBuffer(buffer)", limit = "3")
126126
int write(PMemoryBIO self, Object buffer,
127127
@CachedLibrary("buffer") PythonObjectLibrary lib) {
128-
if (self.getBio().didWriteEOF()) {
128+
if (self.didWriteEOF()) {
129129
throw raise(SSLError, "cannot write() after write_eof()");
130130
}
131131
try {
132132
byte[] bytes = lib.getBufferBytes(buffer);
133133
int len = lib.getBufferLength(buffer);
134-
self.getBio().write(bytes, len);
134+
self.write(bytes, len);
135135
return len;
136136
} catch (OverflowException e) {
137137
throw raise(MemoryError);
@@ -152,7 +152,7 @@ Object error(Object self, Object arg) {
152152
abstract static class WriteEOFNode extends PythonUnaryBuiltinNode {
153153
@Specialization
154154
static PNone writeEOF(PMemoryBIO self) {
155-
self.getBio().writeEOF();
155+
self.writeEOF();
156156
return PNone.NONE;
157157
}
158158
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ssl/PMemoryBIO.java

Lines changed: 124 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,20 +40,140 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.ssl;
4242

43+
import java.nio.ByteBuffer;
44+
4345
import com.oracle.graal.python.builtins.objects.object.PythonObject;
46+
import com.oracle.graal.python.util.OverflowException;
47+
import com.oracle.graal.python.util.PythonUtils;
4448
import com.oracle.truffle.api.object.Shape;
4549

4650
/**
47-
* Python wrapper around {@link MemoryBIO} objects which emulate OpenSSL's BIO interface.
51+
* Our rough equivalent of OpenSSL memory BIO objects used as buffers when performing SSL
52+
* wrapping/unwrapping. They are similar to Java {@link ByteBuffer}, but they have a separate
53+
* position for reading and writing.
4854
*/
4955
public class PMemoryBIO extends PythonObject {
50-
private final MemoryBIO bio = new MemoryBIO();
56+
57+
private byte[] bytes = new byte[0];
58+
private int readPosition;
59+
private int writePosition;
60+
private boolean eofWritten;
5161

5262
public PMemoryBIO(Object pythonClass, Shape instanceShape) {
5363
super(pythonClass, instanceShape);
5464
}
5565

56-
public MemoryBIO getBio() {
57-
return bio;
66+
/**
67+
* Get number of bytes that can be read from this BIO.
68+
*/
69+
public int getPending() {
70+
return writePosition - readPosition;
71+
}
72+
73+
/**
74+
* Wrap into a {@link ByteBuffer} meant for reading the data of this BIO. It is necessary to
75+
* call {@link #applyRead(ByteBuffer)} after performing the read to propagate the updated
76+
* positions.
77+
*/
78+
public ByteBuffer getBufferForReading() {
79+
return ByteBuffer.wrap(bytes, readPosition, getPending());
80+
}
81+
82+
/**
83+
* Update read position from a buffer previously obtained using {@link #getBufferForReading()}
84+
*/
85+
public void applyRead(ByteBuffer buffer) {
86+
readPosition = buffer.position();
87+
assert readPosition <= bytes.length;
88+
assert readPosition <= writePosition;
89+
}
90+
91+
/**
92+
* Wrap into a {@link ByteBuffer} meant for writing the data into this BIO. It is necessary to
93+
* call {@link #applyWrite(ByteBuffer)} after performing the read to propagate the updated
94+
* positions.
95+
*
96+
* @see #ensureWriteCapacity(int)
97+
*/
98+
public ByteBuffer getBufferForWriting() {
99+
return ByteBuffer.wrap(bytes, writePosition, bytes.length - writePosition);
100+
}
101+
102+
/**
103+
* Update write position from a buffer previously obtained using {@link #getBufferForWriting()}
104+
*/
105+
public void applyWrite(ByteBuffer buffer) {
106+
writePosition = buffer.position();
107+
assert writePosition <= bytes.length;
108+
assert readPosition <= writePosition;
109+
}
110+
111+
/**
112+
* Make sure that at least {@code capacity} bytes can be written into this BIO. Disposes of the
113+
* already read part of the buffer when applicable.
114+
*
115+
* @param capacity Required capacity in bytes
116+
*/
117+
public void ensureWriteCapacity(int capacity) throws OverflowException {
118+
if (bytes.length - writePosition < capacity) {
119+
int pending = getPending();
120+
if (bytes.length - pending < capacity) {
121+
byte[] newBytes = new byte[PythonUtils.addExact(capacity, pending)];
122+
PythonUtils.arraycopy(bytes, readPosition, newBytes, 0, pending);
123+
bytes = newBytes;
124+
} else {
125+
PythonUtils.arraycopy(bytes, readPosition, bytes, 0, pending);
126+
}
127+
readPosition = 0;
128+
writePosition = pending;
129+
}
130+
}
131+
132+
/**
133+
* Read at most {@code lenght} bytes from this BIO into a byte array.
134+
*
135+
* @param length Maximum number of bytes to be read. Can be more than the actual size
136+
* @return A new byte array with the read content. Can be empty if there is no data to be read.
137+
*/
138+
public byte[] read(int length) {
139+
int len = Math.min(length, getPending());
140+
byte[] to = new byte[len];
141+
PythonUtils.arraycopy(bytes, readPosition, to, 0, len);
142+
readPosition += len;
143+
return to;
144+
}
145+
146+
/**
147+
* Write entire bytearray into this BIO.
148+
*
149+
* @param from Data to be written
150+
* @param length Lenght of data to be written
151+
*/
152+
public void write(byte[] from, int length) throws OverflowException {
153+
ensureWriteCapacity(length);
154+
PythonUtils.arraycopy(from, 0, bytes, writePosition, Math.min(length, from.length));
155+
writePosition += length;
156+
}
157+
158+
public boolean didWriteEOF() {
159+
return eofWritten;
160+
}
161+
162+
/**
163+
* Return if we reached an EOF marker.
164+
*/
165+
public boolean isEOF() {
166+
return eofWritten && getPending() == 0;
167+
}
168+
169+
/**
170+
* Write an EOF marker.
171+
*/
172+
public void writeEOF() {
173+
this.eofWritten = true;
174+
}
175+
176+
public byte getByte(int offset) {
177+
return bytes[readPosition + offset];
58178
}
59179
}

0 commit comments

Comments
 (0)