|
68 | 68 | import com.oracle.graal.python.builtins.PythonBuiltins;
|
69 | 69 | import com.oracle.graal.python.builtins.objects.PNone;
|
70 | 70 | import com.oracle.graal.python.builtins.objects.bytes.PBytes;
|
| 71 | +import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes; |
| 72 | +import com.oracle.graal.python.builtins.objects.common.SequenceStorageNodes.NoGeneralizationNode; |
71 | 73 | import com.oracle.graal.python.builtins.objects.exception.OSErrorEnum;
|
72 | 74 | import com.oracle.graal.python.nodes.SpecialMethodNames;
|
73 | 75 | import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
|
|
77 | 79 | import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
|
78 | 80 | import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
|
79 | 81 | import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
|
| 82 | +import com.oracle.graal.python.nodes.util.CastToByteNode; |
80 | 83 | import com.oracle.graal.python.nodes.util.CastToIndexNode;
|
81 | 84 | import com.oracle.graal.python.nodes.util.ChannelNodes.ReadByteFromChannelNode;
|
82 | 85 | import com.oracle.graal.python.nodes.util.ChannelNodes.ReadFromChannelNode;
|
83 | 86 | import com.oracle.graal.python.runtime.sequence.storage.ByteSequenceStorage;
|
84 | 87 | import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
85 | 88 | import com.oracle.truffle.api.dsl.Cached;
|
86 | 89 | import com.oracle.truffle.api.dsl.GenerateNodeFactory;
|
87 |
| -import com.oracle.truffle.api.dsl.ImportStatic; |
88 | 90 | import com.oracle.truffle.api.dsl.NodeFactory;
|
89 | 91 | import com.oracle.truffle.api.dsl.Specialization;
|
90 | 92 | import com.oracle.truffle.api.dsl.TypeSystemReference;
|
@@ -290,24 +292,43 @@ PBytes read(PMMap self, Object n,
|
290 | 292 | abstract static class ReadlineNode extends PythonBuiltinNode {
|
291 | 293 |
|
292 | 294 | @Specialization
|
293 |
| - @TruffleBoundary |
294 |
| - Object readline(PMMap self) { |
| 295 | + Object readline(PMMap self, |
| 296 | + @Cached("createAppend()") SequenceStorageNodes.AppendNode appendNode) { |
295 | 297 |
|
296 | 298 | try {
|
297 | 299 | ByteBuffer buf = ByteBuffer.allocate(4096);
|
298 | 300 | SeekableByteChannel channel = self.getChannel();
|
| 301 | + ByteSequenceStorage res = new ByteSequenceStorage(16); |
299 | 302 | // search for newline char
|
300 |
| - int nread; |
301 |
| - while ((nread = channel.read(buf)) > 0) { |
302 |
| - for (int i = 0; i < buf.remaining(); i++) { |
303 |
| - |
| 303 | + outer: while (readIntoBuffer(channel, buf) > 0) { |
| 304 | + buf.flip(); |
| 305 | + while (buf.hasRemaining()) { |
| 306 | + byte b = buf.get(); |
| 307 | + // CPython really tests for '\n' only |
| 308 | + if (b != (byte) '\n') { |
| 309 | + appendNode.execute(res, b); |
| 310 | + } else { |
| 311 | + // recover correct position (i.e. number of remaining bytes in buffer) |
| 312 | + channel.position(channel.position() - buf.remaining() - 1); |
| 313 | + break outer; |
| 314 | + } |
304 | 315 | }
|
| 316 | + buf.clear(); |
305 | 317 | }
|
306 |
| - return null; |
| 318 | + return factory().createBytes(res); |
307 | 319 | } catch (IOException e) {
|
308 | 320 | throw raise(PythonBuiltinClassType.OSError, e.getMessage());
|
309 | 321 | }
|
310 | 322 | }
|
| 323 | + |
| 324 | + @TruffleBoundary(allowInlining = true) |
| 325 | + private static int readIntoBuffer(SeekableByteChannel ch, ByteBuffer dst) throws IOException { |
| 326 | + return ch.read(dst); |
| 327 | + } |
| 328 | + |
| 329 | + protected static SequenceStorageNodes.AppendNode createAppend() { |
| 330 | + return SequenceStorageNodes.AppendNode.create(() -> NoGeneralizationNode.create(CastToByteNode.INVALID_BYTE_VALUE)); |
| 331 | + } |
311 | 332 | }
|
312 | 333 |
|
313 | 334 | @Builtin(name = "seek", fixedNumOfPositionalArgs = 1)
|
|
0 commit comments