diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java index f52c8e64823a2448a5245895889ef20965acb89f..69d387f4296dabcfd29c30a66dfddbfad7550eeb 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java @@ -48,6 +48,7 @@ import com.oracle.truffle.r.parser.ast.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.RContext.ConsoleHandler; import com.oracle.truffle.r.runtime.Utils.DebugExitException; +import com.oracle.truffle.r.runtime.conn.*; import com.oracle.truffle.r.runtime.data.*; import com.oracle.truffle.r.runtime.data.RPromise.Closure; import com.oracle.truffle.r.runtime.data.model.*; @@ -113,6 +114,7 @@ public final class REngine implements RContext.Engine { singleton.crashOnFatalError = crashOnFatalErrorArg; singleton.builtinLookup = RBuiltinPackages.getInstance(); singleton.context = RContext.setRuntimeState(singleton, commandArgs, consoleHandler, new RASTHelperImpl(), headless); + StdConnections.initialize(); MaterializedFrame baseFrame = RRuntime.createNonFunctionFrame().materialize(); REnvironment.baseInitialize(globalFrame, baseFrame); loadBase = FastROptions.LoadBase.getValue(); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java index a7eb66db54f3c6f1bdb23ec98b11e866a387058c..8377d68b63e9d5191bbf6eff6b44127fecc2341f 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java @@ -44,15 +44,6 @@ public class CountFields { byte[] convbuf = new byte[100]; InputStream is; - private void checkClose() { - if (wasopen) { - try { - con.close(); - } catch (IOException ex) { - // Ignore - } - } - } } @TruffleBoundary @@ -61,7 +52,6 @@ public class CountFields { data.sepchar = sepChar; data.comchar = comChar; data.quoteset = quoteSet; - data.is = file.getInputStream(); if (file.isStdin()) { data.ttyflag = true; @@ -70,6 +60,8 @@ public class CountFields { data.ttyflag = false; } + data.wasopen = file.isOpen(); + data.save = 0; int quote = 0; int inquote = 0; @@ -78,90 +70,89 @@ public class CountFields { int blocksize = SCAN_BLOCKSIZE; int[] ans = new int[blocksize]; - while (true) { - int c = scanchar(inquote, data); - if (c == R_EOF) { - if (nfields != 0) { - ans[nlines] = nfields; - } else { - nlines--; - } - break; - } else if (c == '\n') { - if (inquote != 0) { - ans[nlines] = RRuntime.INT_NA; - nlines++; - } else if (nfields > 0 || !blskip) { - ans[nlines] = nfields; - nlines++; - nfields = 0; - inquote = 0; - } - if (nlines == blocksize) { - int[] bns = ans; - blocksize = 2 * blocksize; - ans = new int[blocksize]; - System.arraycopy(bns, 0, ans, 0, bns.length); - } - continue; - } else if (data.sepchar != 0) { - if (nfields == 0) - nfields++; - if (inquote != 0 && c == R_EOF) { - data.checkClose(); - throw new IllegalStateException("quoted string on line " + inquote + " terminated by EOF"); - } - if (inquote != 0 && c == quote) - inquote = 0; - else if (data.quoteset.indexOf(c) > 0) { - inquote = nlines + 1; - quote = c; - } - if (c == data.sepchar && inquote == 0) - nfields++; - } else if (!Rspace(c)) { - if (data.quoteset.indexOf(c) > 0) { - quote = c; - inquote = nlines + 1; - while ((c = scanchar(inquote, data)) != quote) { - if (c == R_EOF) { - data.checkClose(); - throw new IllegalStateException("quoted string on line " + inquote + " terminated by EOF"); - } else if (c == '\n') { - ans[nlines] = RRuntime.INT_NA; - nlines++; - if (nlines == blocksize) { - int[] bns = ans; - blocksize = 2 * blocksize; - ans = new int[blocksize]; - System.arraycopy(bns, 0, ans, 0, bns.length); + try (RConnection openConn = file.forceOpen("r")) { + data.is = openConn.getInputStream(); + while (true) { + int c = scanchar(inquote, data); + if (c == R_EOF) { + if (nfields != 0) { + ans[nlines] = nfields; + } else { + nlines--; + } + break; + } else if (c == '\n') { + if (inquote != 0) { + ans[nlines] = RRuntime.INT_NA; + nlines++; + } else if (nfields > 0 || !blskip) { + ans[nlines] = nfields; + nlines++; + nfields = 0; + inquote = 0; + } + if (nlines == blocksize) { + int[] bns = ans; + blocksize = 2 * blocksize; + ans = new int[blocksize]; + System.arraycopy(bns, 0, ans, 0, bns.length); + } + continue; + } else if (data.sepchar != 0) { + if (nfields == 0) + nfields++; + if (inquote != 0 && c == R_EOF) { + throw new IllegalStateException("quoted string on line " + inquote + " terminated by EOF"); + } + if (inquote != 0 && c == quote) + inquote = 0; + else if (data.quoteset.indexOf(c) > 0) { + inquote = nlines + 1; + quote = c; + } + if (c == data.sepchar && inquote == 0) + nfields++; + } else if (!Rspace(c)) { + if (data.quoteset.indexOf(c) > 0) { + quote = c; + inquote = nlines + 1; + while ((c = scanchar(inquote, data)) != quote) { + if (c == R_EOF) { + throw new IllegalStateException("quoted string on line " + inquote + " terminated by EOF"); + } else if (c == '\n') { + ans[nlines] = RRuntime.INT_NA; + nlines++; + if (nlines == blocksize) { + int[] bns = ans; + blocksize = 2 * blocksize; + ans = new int[blocksize]; + System.arraycopy(bns, 0, ans, 0, bns.length); + } } } + inquote = 0; + } else { + do { + // if (dbcslocale && btowc(c) == WEOF) + // scanchar2(&data); + c = scanchar(0, data); + } while (!Rspace(c) && c != R_EOF); + if (c == R_EOF) + c = '\n'; + unscanchar(c, data); } - inquote = 0; - } else { - do { - // if (dbcslocale && btowc(c) == WEOF) - // scanchar2(&data); - c = scanchar(0, data); - } while (!Rspace(c) && c != R_EOF); - if (c == R_EOF) - c = '\n'; - unscanchar(c, data); + nfields++; } - nfields++; - } + } } /* * we might have a character that was unscanchar-ed. So pushback if possible */ - // if (data.save && !data.ttyflag && data.wasopen) { - // char line[2] = " "; - // line[0] = (char) data.save; - // con_pushback(data.con, FALSE, line); - // } - data.checkClose(); + if (data.save != 0 && !data.ttyflag && data.wasopen) { + // TODO use more primitive method when available + file.pushBack(RDataFactory.createStringVectorFromScalar(new String(new char[]{(char) data.save})), false); + } if (nlines < 0) { return RNull.instance; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java index a02a9281f8c01c827a69566db211adaed874cc80..2b2002208256f5a57af5dac192d8469932737930 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ConnectionFunctions.java @@ -232,9 +232,9 @@ public abstract class ConnectionFunctions { Object[] data = new Object[NAMES.getLength()]; data[0] = baseCon.getSummaryDescription(); data[1] = baseCon.getClassHr().getDataAt(0); - data[2] = baseCon.getOpenMode().modeString; + data[2] = baseCon.getOpenMode().summaryString(); data[3] = baseCon.getSummaryText(); - data[4] = baseCon.isClosed() || !baseCon.isOpen() ? "closed" : "opened"; + data[4] = baseCon.isOpen() ? "opened" : "closed"; data[5] = baseCon.canRead() ? "yes" : "no"; data[6] = baseCon.canWrite() ? "yes" : "no"; return RDataFactory.createList(data, NAMES); @@ -279,7 +279,7 @@ public abstract class ConnectionFunctions { protected RLogicalVector isOpen(RConnection con, RAbstractIntVector rw) { controlVisibility(); BaseRConnection baseCon = getBaseConnection(con); - boolean result = !baseCon.isClosed() && baseCon.isOpen(); + boolean result = baseCon.isOpen(); switch (rw.getDataAt(0)) { case 0: break; @@ -311,7 +311,7 @@ public abstract class ConnectionFunctions { protected Object close(RConnection con) { forceVisibility(false); try { - con.close(); + con.closeAndDestroy(); } catch (IOException ex) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); } @@ -334,7 +334,7 @@ public abstract class ConnectionFunctions { protected void internalClose(RConnection con) throws RError { try { BaseRConnection baseConn = getBaseConnection(con); - baseConn.internalClose(); + baseConn.close(); } catch (IOException ex) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); } @@ -349,20 +349,14 @@ public abstract class ConnectionFunctions { protected Object readLines(RConnection con, int n, byte ok, @SuppressWarnings("unused") byte warn, @SuppressWarnings("unused") String encoding, @SuppressWarnings("unused") byte skipNul) { // TODO implement all the arguments controlVisibility(); - boolean wasOpen = true; - try { - wasOpen = con.forceOpen("rt"); - String[] lines = con.readLines(n); + try (RConnection openConn = con.forceOpen("rt")) { + String[] lines = openConn.readLines(n); if (n > 0 && lines.length < n && ok == RRuntime.LOGICAL_FALSE) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.TOO_FEW_LINES_READ_LINES); } return RDataFactory.createStringVector(lines, RDataFactory.COMPLETE_VECTOR); } catch (IOException x) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, x.getMessage()); - } finally { - if (!wasOpen) { - internalClose(con); - } } } @@ -385,16 +379,10 @@ public abstract class ConnectionFunctions { @Specialization @TruffleBoundary protected RNull writeLines(RAbstractStringVector text, RConnection con, RAbstractStringVector sep, @SuppressWarnings("unused") byte useBytes) { - boolean wasOpen = true; - try { - wasOpen = con.forceOpen("wt"); - con.writeLines(text, sep.getDataAt(0)); + try (RConnection openConn = con.forceOpen("wt")) { + openConn.writeLines(text, sep.getDataAt(0)); } catch (IOException x) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_WRITING_CONNECTION, x.getMessage()); - } finally { - if (!wasOpen) { - internalClose(con); - } } forceVisibility(false); return RNull.instance; @@ -527,20 +515,14 @@ public abstract class ConnectionFunctions { @TruffleBoundary protected RStringVector readChar(RConnection con, RAbstractIntVector nchars, RAbstractLogicalVector useBytes) { controlVisibility(); - boolean wasOpen = true; - try { - wasOpen = con.forceOpen("rb"); + try (RConnection openConn = con.forceOpen("rb")) { String[] data = new String[nchars.getLength()]; for (int i = 0; i < data.length; i++) { - data[i] = con.readChar(nchars.getDataAt(i), useBytes.getDataAt(0) == RRuntime.LOGICAL_TRUE); + data[i] = openConn.readChar(nchars.getDataAt(i), useBytes.getDataAt(0) == RRuntime.LOGICAL_TRUE); } return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); } catch (IOException x) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, x.getMessage()); - } finally { - if (!wasOpen) { - internalClose(con); - } } } @@ -561,9 +543,7 @@ public abstract class ConnectionFunctions { @Specialization protected RNull writeChar(RAbstractStringVector object, RConnection con, RAbstractIntVector nchars, RAbstractStringVector eos, byte useBytes) { controlVisibility(); - boolean wasOpen = true; - try { - wasOpen = con.forceOpen("wb"); + try (RConnection openConn = con.forceOpen("wb")) { int length = object.getLength(); for (int i = 0; i < length; i++) { String s = object.getDataAt(i); @@ -572,14 +552,10 @@ public abstract class ConnectionFunctions { if (pad > 0) { RContext.getInstance().setEvalWarning(RError.Message.MORE_CHARACTERS.message); } - con.writeChar(s, pad, eos.getDataAt(i % length), RRuntime.fromLogical(useBytes)); + openConn.writeChar(s, pad, eos.getDataAt(i % length), RRuntime.fromLogical(useBytes)); } } catch (IOException x) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, x.getMessage()); - } finally { - if (!wasOpen) { - internalClose(con); - } } forceVisibility(false); return RNull.instance; @@ -613,14 +589,12 @@ public abstract class ConnectionFunctions { @Specialization protected Object readBin(RConnection con, RAbstractStringVector whatVec, RAbstractIntVector nVec, int size, byte signedArg, byte swapArg) { boolean swap = RRuntime.fromLogical(swapArg); - boolean wasOpen = true; RVector result = null; int n = nVec.getDataAt(0); - try { - if (getBaseConnection(con).getOpenMode().isText()) { + try (RConnection openConn = con.forceOpen("rb")) { + if (getBaseConnection(openConn).getOpenMode().isText()) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ONLY_READ_BINARY_CONNECTION); } - wasOpen = con.forceOpen("rb"); String what = whatVec.getDataAt(0); switch (what) { case "int": @@ -648,10 +622,6 @@ public abstract class ConnectionFunctions { } } catch (IOException x) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, x.getMessage()); - } finally { - if (!wasOpen) { - internalClose(con); - } } return result; } @@ -782,14 +752,12 @@ public abstract class ConnectionFunctions { @Specialization protected Object writeBin(RAbstractVector object, RConnection con, int size, byte swapArg, byte useBytesArg) { boolean swap = RRuntime.fromLogical(swapArg); - boolean wasOpen = true; boolean useBytes = RRuntime.fromLogical(useBytesArg); if (object.getLength() > 0) { - try { - if (getBaseConnection(con).isTextMode()) { + try (RConnection openConn = con.forceOpen("wb")) { + if (getBaseConnection(openConn).isTextMode()) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ONLY_WRITE_BINARY_CONNECTION); } - wasOpen = con.forceOpen("wb"); if (object instanceof RAbstractIntVector) { writeInteger((RAbstractIntVector) object, con, size, swap); } else if (object instanceof RAbstractDoubleVector) { @@ -807,10 +775,6 @@ public abstract class ConnectionFunctions { } } catch (IOException x) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_WRITING_CONNECTION, x.getMessage()); - } finally { - if (!wasOpen) { - internalClose(con); - } } } forceVisibility(false); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java index 6257433b7bf31b5e0e3e00ffe26c857ac6f71c42..f8d2840822b2f2b4fb4f3a0392e09a05c360180e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ForeignFunctions.java @@ -742,22 +742,11 @@ public class ForeignFunctions { quoteSet = s; } } - boolean wasOpen = true; - try { - wasOpen = conn.forceOpen("r"); - return CountFields.execute(conn, sepChar, quoteSet, nskip, RRuntime.fromLogical(blskip), comChar); + try (RConnection openConn = conn.forceOpen("r")) { + return CountFields.execute(openConn, sepChar, quoteSet, nskip, RRuntime.fromLogical(blskip), comChar); } catch (IllegalStateException | IOException ex) { errorProfile.enter(); throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } finally { - if (!wasOpen) { - try { - conn.internalClose(); - } catch (IOException ex) { - errorProfile.enter(); - throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } - } } } @@ -772,22 +761,11 @@ public class ForeignFunctions { Object[] argValues = args.getValues(); RConnection conn = (RConnection) argValues[0]; int nlines = castInt(frame, castVector(frame, argValues[1])); - boolean wasOpen = true; - try { - wasOpen = conn.forceOpen("r"); - return RDataFactory.createStringVector(conn.readLines(nlines), RDataFactory.COMPLETE_VECTOR); + try (RConnection openConn = conn.forceOpen("r")) { + return RDataFactory.createStringVector(openConn.readLines(nlines), RDataFactory.COMPLETE_VECTOR); } catch (IOException ex) { errorProfile.enter(); throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, ex.getMessage()); - } finally { - if (!wasOpen) { - try { - conn.internalClose(); - } catch (IOException ex) { - errorProfile.enter(); - throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } - } } } @@ -921,22 +899,11 @@ public class ForeignFunctions { quoteCol[qi - 1] = true; } } - boolean wasOpen = true; - try { - wasOpen = conn.forceOpen("wt"); - WriteTable.execute(conn, argValues[0], nr, nc, rnamesArg, csep, ceol, cna, cdec.charAt(0), RRuntime.fromLogical(qmethod), quoteCol, quoteRn); + try (RConnection openConn = conn.forceOpen("wt")) { + WriteTable.execute(openConn, argValues[0], nr, nc, rnamesArg, csep, ceol, cna, cdec.charAt(0), RRuntime.fromLogical(qmethod), quoteCol, quoteRn); } catch (IOException | IllegalArgumentException ex) { errorProfile.enter(); throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } finally { - if (!wasOpen) { - try { - conn.internalClose(); - } catch (IOException ex) { - errorProfile.enter(); - throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } - } } return RNull.instance; } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadFunctions.java index 0986ea573554a373416d4217564b6c87c90f3a54..6e9e27bb89fdb0b1381d0170d467394c4eed220f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LoadFunctions.java @@ -37,13 +37,8 @@ public class LoadFunctions { @Specialization protected RStringVector load(VirtualFrame frame, RConnection con, REnvironment envir, @SuppressWarnings("unused") RAbstractLogicalVector verbose) { controlVisibility(); - boolean wasOpen = true; - try { - /* - * The connection may or may not be open (see load.R). - */ - wasOpen = con.forceOpen("rb"); - String s = con.readChar(5, true); + try (RConnection openConn = con.forceOpen("r")) { + String s = openConn.readChar(5, true); if (s.equals("RDA2\n") || s.equals("RDB2\n") || s.equals("RDX2\n")) { Object o = RSerialize.unserialize(con, RArguments.getDepth(frame)); if (!(o instanceof RPairList)) { @@ -78,14 +73,6 @@ public class LoadFunctions { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, iox.getMessage()); } catch (PutException px) { throw RError.error(this.getEncapsulatingSourceSection(), px); - } finally { - if (!wasOpen) { - try { - con.internalClose(); - } catch (IOException ex) { - throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } - } } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java index 3464754010bf1cb3738065a26baa85eb69c3c72e..29995914dae6e713613116bcc3334e518cac96f1 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/ReadDCF.java @@ -47,7 +47,7 @@ public abstract class ReadDCF extends RBuiltinNode { @TruffleBoundary protected RStringVector doReadDCF(RConnection conn, RAbstractStringVector fields, @SuppressWarnings("unused") RNull keepWhite) { DCF dcf = null; - try { + try (RConnection openConn = conn.forceOpen("r")) { dcf = DCF.read(conn.readLines(0)); } catch (IOException ex) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.ERROR_READING_CONNECTION, ex.getMessage()); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java index beb97cee66f0d3dc8adb5d59462e447d34a064fd..84431a25477a1ec03f06fd04a671630bd595bdc8 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SerializeFunctions.java @@ -37,9 +37,6 @@ import com.oracle.truffle.r.runtime.env.*; public class SerializeFunctions { - // TODO This code needs to check for unopened connections as per GnuR, - // which requires more publicly visible support in RConnection - @RBuiltin(name = "unserializeFromConn", kind = INTERNAL, parameterNames = {"conn", "refhook"}) public abstract static class UnserializeFromConn extends RInvisibleBuiltinNode { @Specialization @@ -50,24 +47,14 @@ public class SerializeFunctions { @TruffleBoundary protected Object doUnserializeFromConn(RConnection conn, @SuppressWarnings("unused") REnvironment refhook, int depth) { controlVisibility(); - boolean wasOpen = true; - try { - wasOpen = conn.forceOpen("rb"); - if (!conn.canRead()) { + try (RConnection openConn = conn.forceOpen("rb")) { + if (!openConn.canRead()) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.CONNECTION_NOT_OPEN_READ); } - Object result = RSerialize.unserialize(conn, depth); + Object result = RSerialize.unserialize(openConn, depth); return result; } catch (IOException ex) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } finally { - if (!wasOpen) { - try { - conn.internalClose(); - } catch (IOException ex) { - throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } - } } } @@ -88,28 +75,18 @@ public class SerializeFunctions { @TruffleBoundary protected Object doSerializeToConn(Object object, RConnection conn, byte asciiLogical, @SuppressWarnings("unused") RNull version, @SuppressWarnings("unused") RNull refhook, int depth) { controlVisibility(); - boolean wasOpen = true; - try { + try (RConnection openConn = conn.forceOpen("wb")) { boolean ascii = RRuntime.fromLogical(asciiLogical); - wasOpen = conn.forceOpen("wb"); - if (!conn.canWrite()) { + if (!openConn.canWrite()) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.CONNECTION_NOT_OPEN_WRITE); } - if (!ascii && conn.isTextMode()) { + if (!ascii && openConn.isTextMode()) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.BINARY_CONNECTION_REQUIRED); } - RSerialize.serialize(conn, object, ascii, 2, null, depth); + RSerialize.serialize(openConn, object, ascii, 2, null, depth); return RNull.instance; } catch (IOException ex) { throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } finally { - if (!wasOpen) { - try { - conn.internalClose(); - } catch (IOException ex) { - throw RError.error(getEncapsulatingSourceSection(), RError.Message.GENERIC, ex.getMessage()); - } - } } } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java index aa1b7646afc5289c93b9af7a7bfe3b3a7d8fdfc7..de6302253f52d6bb85f64159aba835effca5783b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/ConnectionSupport.java @@ -80,7 +80,7 @@ public class ConnectionSupport { ReadAppend(new String[]{"a+"}, true, true, true), ReadAppendBinary(new String[]{"a+b"}, false, true, true); - private String[] modeStrings; + public final String[] modeStrings; public final boolean isText; public final boolean readable; public final boolean writeable; @@ -113,15 +113,34 @@ public class ConnectionSupport { */ public static class OpenMode { public final AbstractOpenMode abstractOpenMode; + /** + * When {@link #abstractOpenMode} is {@code Lazy}, this is used to store the default open + * mode, otherwise it is the actual string passed to the open. + */ public final String modeString; - public OpenMode(String modeString) throws IOException { - this(modeString, AbstractOpenMode.getOpenMode(modeString)); + /** + * For connections other than {@link StdConnections}. + */ + + public OpenMode(String modeString, AbstractOpenMode defaultModeForLazy) throws IOException { + this.abstractOpenMode = AbstractOpenMode.getOpenMode(modeString); + this.modeString = abstractOpenMode == AbstractOpenMode.Lazy ? defaultModeForLazy.modeStrings[0] : modeString; } - OpenMode(String modeString, AbstractOpenMode mode) { - this.modeString = modeString; - this.abstractOpenMode = mode; + /** + * For {@link StdConnections}. + */ + OpenMode(AbstractOpenMode mode) throws IOException { + this(mode.modeStrings[0], mode); + } + + /** + * Only used when a lazy connection is actually opened. + */ + OpenMode(String modeString) throws IOException { + // defaultModeForLazy will not be used + this(modeString, null); } public boolean isText() { @@ -135,6 +154,10 @@ public class ConnectionSupport { boolean canWrite() { return abstractOpenMode.writeable; } + + public String summaryString() { + return abstractOpenMode == AbstractOpenMode.Lazy ? "" : modeString; + } } enum ConnectionClass { @@ -158,9 +181,10 @@ public class ConnectionSupport { /** * Class that holds common state for all {@link RConnection} instances. It supports lazy * opening, as required by the R spec, through the {@link #theConnection} field, which - * ultimately holds the actual connection instance when opened. The default implementations of - * the {@link RConnection} methods check whether the connection is open and if not, call - * {@link #createDelegateConnection()} and then forward the operation. The result of + * ultimately holds the actual connection instance when opened. Any builtin that uses a + * connection passed in as argument must call {@link RConnection#forceOpen} to check whether the + * connection is already open. If not already open {@link #forceOpen} will call + * {@link #createDelegateConnection()} to create the actual connection. The result of * {@link #createDelegateConnection()} should be a subclass of {@link DelegateRConnection}, * which subclasses {@link RConnection} directly. A subclass may choose not to use delegation by * overriding the default implementations of the methods in this class. A @@ -186,12 +210,20 @@ public class ConnectionSupport { */ protected boolean closed; + /** + * Supports the auto-close operation for connections opened just for a single operation. + */ + private boolean tempOpened; + /** * if {@link #opened} is {@code true} the {@link OpenMode} that this connection is opened * in, otherwise {@link AbstractOpenMode#Lazy}. */ private OpenMode openMode; + /** + * The classes of the connection, which always includes "connection". + */ private final RStringVector classHr; /** @@ -199,29 +231,41 @@ public class ConnectionSupport { */ protected DelegateRConnection theConnection; + /** + * An integer used to identify the connection to the {@code getAllConnections} builtin. + */ private int descriptor; /** - * The constructor to use for a connection class whose default open mode is not "read", but - * specified explicitly by "lazyMode". + * The constructor for every connection class except {@link StdConnections}. + * + * @param conClass the specific class of the connection, e.g, {@link ConnectionClass#File} + * @param modeString the mode in which the connection should be opened, "" for lazy opening + * @param defaultModeForLazy the mode to use when this connection is opened implicitly + * + */ + protected BaseRConnection(ConnectionClass conClass, String modeString, AbstractOpenMode defaultModeForLazy) throws IOException { + this(conClass, new OpenMode(modeString, defaultModeForLazy)); + setDescriptor(getConnectionIndex()); + } + + /** + * The constructor for {@link StdConnections}. */ - protected BaseRConnection(ConnectionClass conClass, String modeString) throws IOException { - this(conClass, new OpenMode(modeString), false); + protected BaseRConnection(AbstractOpenMode mode, int index) throws IOException { + this(ConnectionClass.Terminal, new OpenMode(mode)); + setDescriptor(index); } /** - * Primitive constructor that just assigns state. Used by {@link StdConnections} as they are - * a special case, but should not be used by other connection types. + * Primitive constructor that just assigns state. */ - protected BaseRConnection(ConnectionClass conClass, OpenMode mode, boolean std) { + private BaseRConnection(ConnectionClass conClass, OpenMode mode) { this.openMode = mode; String[] classes = new String[2]; classes[0] = conClass.printName; classes[1] = "connection"; this.classHr = RDataFactory.createStringVector(classes, RDataFactory.COMPLETE_VECTOR); - if (!std) { - registerConnection(); - } } protected void openNonLazyConnection() throws IOException { @@ -233,7 +277,8 @@ public class ConnectionSupport { /** * A connection is "active" if it has been opened and not yet closed. */ - protected boolean isActive() { + @Override + public boolean isOpen() { return !closed && opened; } @@ -242,7 +287,7 @@ public class ConnectionSupport { */ @Override public boolean canRead() { - if (isActive()) { + if (isOpen()) { return getOpenMode().canRead(); } else { // Might think to check the lazy open mode, but GnuR doesn't @@ -255,7 +300,7 @@ public class ConnectionSupport { */ @Override public boolean canWrite() { - if (isActive()) { + if (isOpen()) { return getOpenMode().canWrite(); } else { // Might think to check the lazy open mode, but GnuR doesn't @@ -271,32 +316,30 @@ public class ConnectionSupport { return getOpenMode().isText(); } - private void registerConnection() { + private static int getConnectionIndex() { for (int i = 3; i < allConnections.length; i++) { if (allConnections[i] == null) { - allConnections[i] = this; - descriptor = i; - return; + return i; } } throw RError.error(RError.Message.ALL_CONNECTIONS_IN_USE); } @Override - public boolean forceOpen(String modeString) throws IOException { - boolean ret = opened; + public RConnection forceOpen(String modeString) throws IOException { if (closed) { throw new IOException(RError.Message.INVALID_CONNECTION.message); } if (!opened) { + tempOpened = true; // internal closed or lazy - if (getOpenMode().abstractOpenMode == AbstractOpenMode.Lazy) { + if (openMode.abstractOpenMode == AbstractOpenMode.Lazy) { // modeString may override the default - openMode = new OpenMode(modeString); + openMode = new OpenMode(modeString == null ? openMode.modeString : modeString); } createDelegateConnection(); } - return ret; + return this; } protected void checkOpen() { @@ -369,22 +412,25 @@ public class ConnectionSupport { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { closed = true; if (theConnection != null) { - theConnection.close(); + theConnection.closeAndDestroy(); } assert allConnections[this.descriptor] != null; allConnections[this.descriptor] = null; } @Override - public void internalClose() throws IOException { - opened = false; - if (theConnection != null) { - DelegateRConnection tc = theConnection; - theConnection = null; - tc.internalClose(); + public void close() throws IOException { + if (tempOpened) { + tempOpened = false; + opened = false; + if (theConnection != null) { + DelegateRConnection tc = theConnection; + theConnection = null; + tc.close(); + } } } @@ -420,6 +466,12 @@ public class ConnectionSupport { return descriptor; } + private void setDescriptor(int index) { + assert allConnections[index] == null; + this.descriptor = index; + allConnections[index] = this; + } + public static BaseRConnection getConnection(int descriptor) { if (descriptor >= allConnections.length || allConnections[descriptor] == null) { throw RError.error(RError.Message.INVALID_CONNECTION); @@ -452,10 +504,6 @@ public class ConnectionSupport { return classHr; } - public boolean isOpen() { - return opened; - } - public boolean isClosed() { return closed; } @@ -630,7 +678,12 @@ public class ConnectionSupport { } @Override - public boolean forceOpen(String modeString) throws IOException { + public boolean isOpen() { + return base.isOpen(); + } + + @Override + public RConnection forceOpen(String modeString) throws IOException { return base.forceOpen(modeString); } @@ -739,7 +792,11 @@ public class ConnectionSupport { protected final String path; protected BasePathRConnection(String path, ConnectionClass connectionClass, String modeString) throws IOException { - super(connectionClass, modeString); + this(path, connectionClass, modeString, AbstractOpenMode.Read); + } + + protected BasePathRConnection(String path, ConnectionClass connectionClass, String modeString, AbstractOpenMode defaultLazyOpenMode) throws IOException { + super(connectionClass, modeString, defaultLazyOpenMode); this.path = Utils.tildeExpand(path); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java index 9cccbc2b44eba8804ce9d5c393eea7e616776a88..60671f03be917f1941cc984facb31faea3fbfcc0 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/FileConnections.java @@ -105,13 +105,13 @@ public class FileConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; - internalClose(); + close(); } @Override - public void internalClose() throws IOException { + public void close() throws IOException { inputStream.close(); } @@ -147,13 +147,13 @@ public class FileConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; - internalClose(); + close(); } @Override - public void internalClose() throws IOException { + public void close() throws IOException { outputStream.close(); } @@ -198,13 +198,13 @@ public class FileConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; - internalClose(); + close(); } @Override - public void internalClose() throws IOException { + public void close() throws IOException { inputStream.close(); } @@ -234,13 +234,13 @@ public class FileConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; - internalClose(); + close(); } @Override - public void internalClose() throws IOException { + public void close() throws IOException { flush(); outputStream.close(); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/GZIPConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/GZIPConnections.java index a1b57699f483c755e1eaf6e6b30f637cb7ab85b1..b22b9c321de14927cb7d05d87e43b82fca931fbc 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/GZIPConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/GZIPConnections.java @@ -33,12 +33,14 @@ import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.model.*; public class GZIPConnections { + private static final int GZIP_BUFFER_SIZE = (2 << 20); + /** * Base class for all modes of gzfile connections. */ public static class GZIPRConnection extends BasePathRConnection { public GZIPRConnection(String path, String modeString) throws IOException { - super(path, ConnectionClass.GZFile, modeString); + super(path, ConnectionClass.GZFile, modeString, AbstractOpenMode.ReadBinary); openNonLazyConnection(); } @@ -70,7 +72,7 @@ public class GZIPConnections { GZIPInputRConnection(GZIPRConnection base) throws IOException { super(base); - inputStream = new GZIPInputStream(new FileInputStream(base.path), RConnection.GZIP_BUFFER_SIZE); + inputStream = new GZIPInputStream(new FileInputStream(base.path), GZIP_BUFFER_SIZE); } @Override @@ -99,13 +101,13 @@ public class GZIPConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; - internalClose(); + close(); } @Override - public void internalClose() throws IOException { + public void close() throws IOException { inputStream.close(); } @@ -116,7 +118,7 @@ public class GZIPConnections { GZIPOutputRConnection(GZIPRConnection base) throws IOException { super(base); - outputStream = new GZIPOutputStream(new FileOutputStream(base.path), RConnection.GZIP_BUFFER_SIZE); + outputStream = new GZIPOutputStream(new FileOutputStream(base.path), GZIP_BUFFER_SIZE); } @Override @@ -125,13 +127,13 @@ public class GZIPConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; - internalClose(); + close(); } @Override - public void internalClose() throws IOException { + public void close() throws IOException { flush(); outputStream.close(); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java index 2b26d002949b54d3641dcd6d84a1197af61c45f0..2c3f7182e41b1e7a148f34c36b1ea0aa4798a20f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/RConnection.java @@ -32,10 +32,10 @@ import com.oracle.truffle.r.runtime.data.model.*; /** * Denotes an R {@code connection} instance used in the {@code base} I/O library. + * + * TODO Refactor the pushBack code into ConnectionsSupport */ -public abstract class RConnection implements RClassHierarchy { - - public static final int GZIP_BUFFER_SIZE = (2 << 20); +public abstract class RConnection implements RClassHierarchy, AutoCloseable { private LinkedList<String> pushBack; @@ -158,7 +158,7 @@ public abstract class RConnection implements RClassHierarchy { /** * Close the connection. The corresponds to the {@code R close} function. */ - public abstract void close() throws IOException; + public abstract void closeAndDestroy() throws IOException; /** * Returns {@ode true} iff we can read on this connection. @@ -171,30 +171,33 @@ public abstract class RConnection implements RClassHierarchy { public abstract boolean canWrite(); /** - * Forces the connection open. If the connection was already open, returns {@code true} and does - * nothing. Otherwise, tries to open the connection in the given mode, returning {@code false} - * if successful and throwing an {@link IOException} if not. + * Forces the connection open. If the connection was already open does nothing. Otherwise, tries + * to open the connection in the given mode. In either case returns an opened connection. + * + * builtins that need to ensure that a connection is open should use thr try-with-resources + * pattern, e.g: * - * For builtins that implicitly open/close a connection, the following idiom should be used: * * <pre> * boolean wasOpen = true; - * try { - * wasOpen = conn.forceOpen(mode); - * } finally { - * if (!wasOpen) { - * conn.internalClose(); - * } + * try (RConnection openConn = conn.forceOpen(mode)) { + * // work with openConn + * } catch (IOException ex) { + * throw RError ... * } * </pre> + * + * N.B. While the returned value likely will be the same as {@code this}, callers should not + * rely on it but should use the result in the body of the {@code try} block. If the connection + * cannot be opened {@link IOException} is thrown. */ - public abstract boolean forceOpen(String modeString) throws IOException; + public abstract RConnection forceOpen(String modeString) throws IOException; /** * Closes the internal state of the stream, but does not set the connection state to "closed", * i.e., allowing it to be re-opened. */ - public abstract void internalClose() throws IOException; + public abstract void close() throws IOException; /** * Implements {@link RClassHierarchy}. @@ -289,4 +292,9 @@ public abstract class RConnection implements RClassHierarchy { */ public abstract boolean isTextMode(); + /** + * Returns {@code true} iff this connection is open. + */ + public abstract boolean isOpen(); + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/SocketConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/SocketConnections.java index a56f6bf310b2a6a5a5bbac3e307b8463fa3cf715..aee838251c79dbf807f3dfa9141f5e4f1d2b9bbf 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/SocketConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/SocketConnections.java @@ -46,7 +46,7 @@ public class SocketConnections { protected final int timeout; public RSocketConnection(String modeString, boolean server, String host, int port, boolean blocking, int timeout) throws IOException { - super(ConnectionClass.Socket, modeString); + super(ConnectionClass.Socket, modeString, AbstractOpenMode.Read); this.server = server; this.host = host; this.port = port; @@ -142,13 +142,13 @@ public class SocketConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; - internalClose(); + close(); } @Override - public void internalClose() throws IOException { + public void close() throws IOException { socket.close(); } @@ -167,8 +167,8 @@ public class SocketConnections { } @Override - public void internalClose() throws IOException { - super.internalClose(); + public void close() throws IOException { + super.close(); serverSocket.close(); } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java index 3b43c51c58b0e711802a47b205a0847e0cb051bf..fc499f6425973db66f72c40797ecdb8c2d673b21 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/StdConnections.java @@ -33,14 +33,28 @@ import com.oracle.truffle.r.runtime.conn.ConnectionSupport.*; import com.oracle.truffle.r.runtime.data.model.*; public class StdConnections { + private static StdinConnection stdin; + private static StdoutConnection stdout; + private static StdoutConnection stderr; + + public static void initialize() { + // This ensures the connections are initialized on engine startup. + try { + stdin = new StdinConnection(); + stdout = new StdoutConnection(false); + stderr = new StdoutConnection(true); + } catch (IOException ex) { + Utils.fail("failed to open stdconnections:"); + } + } + /** * Subclasses are special in that they do not use delegation as the connection is always open. */ private abstract static class StdConnection extends BaseRConnection { - StdConnection(OpenMode openMode, int index) { - super(ConnectionClass.Terminal, openMode, true); + StdConnection(AbstractOpenMode openMode, int index) throws IOException { + super(openMode, index); this.opened = true; - ConnectionSupport.setStdConnection(index, this); } @Override @@ -54,7 +68,7 @@ public class StdConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { throw new IOException(RError.Message.CANNOT_CLOSE_STANDARD_CONNECTIONS.message); } @@ -79,15 +93,15 @@ public class StdConnections { } @Override - public boolean forceOpen(String modeString) { - return true; + public RConnection forceOpen(String modeString) { + throw RInternalError.shouldNotReachHere(); } } private static class StdinConnection extends StdConnection { - StdinConnection() { - super(new OpenMode("r", AbstractOpenMode.Read), 0); + StdinConnection() throws IOException { + super(AbstractOpenMode.Read, 0); } @Override @@ -129,8 +143,6 @@ public class StdConnections { } - private static final StdinConnection stdin = new StdinConnection(); - public static RConnection getStdin() { return stdin; } @@ -139,8 +151,8 @@ public class StdConnections { private final boolean isErr; - StdoutConnection(boolean isErr) { - super(new OpenMode("w", AbstractOpenMode.Write), isErr ? 2 : 1); + StdoutConnection(boolean isErr) throws IOException { + super(AbstractOpenMode.Write, isErr ? 2 : 1); this.opened = true; this.isErr = isErr; } @@ -186,14 +198,10 @@ public class StdConnections { } } - private static final StdoutConnection stdout = new StdoutConnection(false); - public static RConnection getStdout() { return stdout; } - private static final StdoutConnection stderr = new StdoutConnection(true); - public static RConnection getStderr() { return stderr; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java index 0f23c4358637248dc84d447a6fd40b88c3c7f0dc..e9488708c15c1e3e0efdc545bcd5941ff37f0777 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/TextConnections.java @@ -38,7 +38,7 @@ public class TextConnections { protected REnvironment env; public TextRConnection(String nm, RAbstractStringVector object, REnvironment env, String modeString) throws IOException { - super(ConnectionClass.Text, modeString); + super(ConnectionClass.Text, modeString, AbstractOpenMode.Read); this.nm = nm; this.object = object; this.env = env; @@ -105,12 +105,12 @@ public class TextConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; } @Override - public void internalClose() { + public void close() { } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/URLConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/URLConnections.java index 41bc5cfaa70e19406b789ebd1b2af3186f0aecdb..94ae7582e10f813332198d80d8fe1d5aa85ebad4 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/URLConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/URLConnections.java @@ -36,7 +36,7 @@ public class URLConnections { protected final String urlString; public URLRConnection(String url, String modeString) throws IOException { - super(ConnectionClass.URL, modeString); + super(ConnectionClass.URL, modeString, AbstractOpenMode.Read); this.urlString = url; } @@ -90,13 +90,13 @@ public class URLConnections { } @Override - public void close() throws IOException { + public void closeAndDestroy() throws IOException { base.closed = true; - internalClose(); + close(); } @Override - public void internalClose() throws IOException { + public void close() throws IOException { inputStream.close(); }