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 17668e2b790690063a1eec62765b5357b37ca4a6..96b23862edb16fb271658697755d570303163c1a 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 @@ -59,6 +59,7 @@ import java.nio.ShortBuffer; import java.nio.channels.ByteChannel; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -90,7 +91,6 @@ import com.oracle.truffle.r.runtime.conn.SocketConnections.RSocketConnection; import com.oracle.truffle.r.runtime.conn.TextConnections.TextRConnection; import com.oracle.truffle.r.runtime.conn.URLConnections.URLRConnection; import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RComplexVector; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDoubleVector; @@ -106,13 +106,12 @@ import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.nodes.RBaseNode; @@ -1066,90 +1065,83 @@ public abstract class ConnectionFunctions { return WriteDataNodeGen.create(); } + @TruffleBoundary private static ByteBuffer allocate(int capacity, boolean swap) { ByteBuffer buffer = ByteBuffer.allocate(capacity); checkOrder(buffer, swap); return buffer; } - @Specialization - protected ByteBuffer writeInteger(RAbstractIntVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) { - int length = object.getLength(); - ByteBuffer buffer = allocate(4 * length, swap); - for (int i = 0; i < length; i++) { - int value = object.getDataAt(i); - buffer.putInt(value); - } - return buffer; - } - - @Specialization - protected ByteBuffer writeDouble(RAbstractDoubleVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) { - int length = object.getLength(); - ByteBuffer buffer = allocate(8 * length, swap); - for (int i = 0; i < length; i++) { - double value = object.getDataAt(i); - buffer.putDouble(value); - } - return buffer; - } - - @Specialization - protected ByteBuffer writeComplex(RAbstractComplexVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) { - int length = object.getLength(); - ByteBuffer buffer = allocate(16 * length, swap); - for (int i = 0; i < length; i++) { - RComplex complex = object.getDataAt(i); - double re = complex.getRealPart(); - double im = complex.getImaginaryPart(); - buffer.putDouble(re); - buffer.putDouble(im); - } - return buffer; - } - - @Specialization @TruffleBoundary - protected ByteBuffer writeString(RAbstractStringVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) { - int length = object.getLength(); - byte[][] data = new byte[length][]; - int totalLength = 0; - for (int i = 0; i < length; i++) { - String s = object.getDataAt(i); - // There is no special encoding for NA_character_ - data[i] = s.getBytes(); - totalLength = totalLength + data[i].length + 1; // zero pad - } - - ByteBuffer buffer = allocate(totalLength, swap); - for (int i = 0; i < length; i++) { - buffer.put(data[i]); - buffer.put((byte) 0); - } - return buffer; - } + private static byte[] encodeString(String s) { + return s.getBytes(StandardCharsets.UTF_8); + } + + @Specialization(guards = "objectAccess.supports(object)") + protected ByteBuffer write(RAbstractVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes, + @Cached("object.access()") VectorAccess objectAccess) { + try (SequentialIterator iter = objectAccess.access(object)) { + int length = objectAccess.getLength(iter); + + ByteBuffer buffer; + switch (objectAccess.getType()) { + case Integer: + buffer = allocate(4 * length, swap); + while (objectAccess.next(iter)) { + buffer.putInt(objectAccess.getInt(iter)); + } + return buffer; + case Double: + buffer = allocate(8 * length, swap); + while (objectAccess.next(iter)) { + buffer.putDouble(objectAccess.getDouble(iter)); + } + return buffer; + case Complex: + buffer = allocate(16 * length, swap); + while (objectAccess.next(iter)) { + buffer.putDouble(objectAccess.getComplexR(iter)); + buffer.putDouble(objectAccess.getComplexI(iter)); + } + return buffer; + case Character: + byte[][] data = new byte[length][]; + int totalLength = 0; + while (objectAccess.next(iter)) { + // There is no special encoding for NA_character_ + data[iter.getIndex()] = encodeString(objectAccess.getString(iter)); + // zero pad + totalLength = totalLength + data[iter.getIndex()].length + 1; + } - @Specialization - protected ByteBuffer writeLogical(RAbstractLogicalVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) { - // encoded as ints, with FALSE=0, TRUE=1, NA=Integer_NA_ - int length = object.getLength(); - ByteBuffer buffer = allocate(4 * length, swap); - for (int i = 0; i < length; i++) { - byte value = object.getDataAt(i); - int encoded = RRuntime.isNA(value) ? RRuntime.INT_NA : value == RRuntime.LOGICAL_FALSE ? 0 : 1; - buffer.putInt(encoded); + buffer = allocate(totalLength, swap); + for (int i = 0; i < length; i++) { + buffer.put(data[i]); + buffer.put((byte) 0); + } + return buffer; + case Logical: + buffer = allocate(4 * length, swap); + while (objectAccess.next(iter)) { + buffer.putInt(objectAccess.getInt(iter)); // converted to int + } + return buffer; + case Raw: + buffer = allocate(length, swap); + while (objectAccess.next(iter)) { + buffer.put(objectAccess.getRaw(iter)); + } + return buffer; + default: + throw RInternalError.shouldNotReachHere(); + } } - return buffer; } - @Specialization - protected ByteBuffer writeRaw(RAbstractRawVector object, @SuppressWarnings("unused") int size, boolean swap, @SuppressWarnings("unused") boolean useBytes) { - int length = object.getLength(); - ByteBuffer buffer = allocate(length, swap); - for (int i = 0; i < length; i++) { - buffer.put(object.getRawDataAt(i)); - } - return buffer; + @Specialization(replaces = "write") + @TruffleBoundary + protected ByteBuffer writeGeneric(RAbstractVector object, int size, boolean swap, boolean useBytes) { + return write(object, size, swap, useBytes, object.slowPathAccess()); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java index 7387acb53a474e1a3cc57427742902df405fc1ec..6d1ef76310482907a94d3283240d4d629a583f9c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawFunctions.java @@ -40,9 +40,11 @@ import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; /** * Conversion and manipulation of objects of type "raw". @@ -57,17 +59,26 @@ public class RawFunctions { casts.arg("x").defaultError(RError.Message.ARG_MUST_BE_CHARACTER_VECTOR_LENGTH_ONE).mustBe(stringValue()).asStringVector().mustBe(notEmpty()); } - @Specialization - protected RRawVector charToRaw(RAbstractStringVector x) { - if (x.getLength() > 1) { - warning(RError.Message.ARG_SHOULD_BE_CHARACTER_VECTOR_LENGTH_ONE); - } - String s = x.getDataAt(0); - byte[] data = new byte[s.length()]; - for (int i = 0; i < data.length; i++) { - data[i] = (byte) s.charAt(i); + @Specialization(guards = "xAccess.supports(x)") + protected RRawVector charToRaw(RAbstractStringVector x, + @Cached("x.access()") VectorAccess xAccess) { + try (RandomIterator iter = xAccess.randomAccess(x)) { + if (xAccess.getLength(iter) != 1) { + warning(RError.Message.ARG_SHOULD_BE_CHARACTER_VECTOR_LENGTH_ONE); + } + String s = xAccess.getString(iter, 0); + byte[] data = new byte[s.length()]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) s.charAt(i); + } + return RDataFactory.createRawVector(data); } - return RDataFactory.createRawVector(data); + } + + @Specialization(replaces = "charToRaw") + @TruffleBoundary + protected RRawVector charToRawGeneric(RAbstractStringVector x) { + return charToRaw(x, x.slowPathAccess()); } } @@ -80,28 +91,45 @@ public class RawFunctions { casts.arg("multiple").defaultError(RError.Message.INVALID_LOGICAL).asLogicalVector().findFirst().mustNotBeNA().map(toBoolean()); } - @Specialization @TruffleBoundary - protected RStringVector rawToChar(RAbstractRawVector x, boolean multiple) { - RStringVector result; - if (multiple) { - String[] data = new String[x.getLength()]; - for (int i = 0; i < data.length; i++) { - data[i] = new String(new byte[]{x.getRawDataAt(i)}); - } - result = RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); - } else { - int j = 0; - byte[] data = new byte[x.getLength()]; - for (int i = 0; i < data.length; i++) { - byte b = x.getRawDataAt(i); - if (b != 0) { - data[j++] = b; + private static String createString(int j, byte[] data) { + return new String(data, 0, j); + } + + @TruffleBoundary + private static String createString(byte value) { + return new String(new byte[]{value}); + } + + @Specialization(guards = "xAccess.supports(x)") + protected Object rawToChar(RAbstractRawVector x, boolean multiple, + @Cached("x.access()") VectorAccess xAccess) { + try (SequentialIterator iter = xAccess.access(x)) { + if (multiple) { + String[] data = new String[xAccess.getLength(iter)]; + while (xAccess.next(iter)) { + byte value = xAccess.getRaw(iter); + data[iter.getIndex()] = createString(value); + } + return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR); + } else { + int j = 0; + byte[] data = new byte[xAccess.getLength(iter)]; + while (xAccess.next(iter)) { + byte b = xAccess.getRaw(iter); + if (b != 0) { + data[j++] = b; + } } + return createString(j, data); } - result = RDataFactory.createStringVectorFromScalar(new String(data, 0, j)); } - return result; + } + + @Specialization(replaces = "rawToChar") + @TruffleBoundary + protected Object rawToCharGeneric(RAbstractRawVector x, boolean multiple) { + return rawToChar(x, multiple, x.slowPathAccess()); } } @@ -114,23 +142,30 @@ public class RawFunctions { casts.arg("n").defaultError(RError.Message.MUST_BE_SMALL_INT, "shift").asIntegerVector().findFirst().mustNotBeNA().mustBe(gte(-8).and(lte(8))); } - @Specialization + @Specialization(guards = "xAccess.supports(x)") protected RRawVector rawShift(RAbstractRawVector x, int n, - @Cached("createBinaryProfile()") ConditionProfile negativeShiftProfile) { - byte[] data = new byte[x.getLength()]; - if (negativeShiftProfile.profile(n < 0)) { - for (int i = 0; i < data.length; i++) { - data[i] = (byte) ((x.getRawDataAt(i) & 0xff) >> (-n)); - } - } else { - for (int i = 0; i < data.length; i++) { - data[i] = (byte) (x.getRawDataAt(i) << n); + @Cached("createBinaryProfile()") ConditionProfile negativeShiftProfile, + @Cached("x.access()") VectorAccess xAccess) { + try (SequentialIterator iter = xAccess.access(x)) { + byte[] data = new byte[xAccess.getLength(iter)]; + if (negativeShiftProfile.profile(n < 0)) { + while (xAccess.next(iter)) { + data[iter.getIndex()] = (byte) ((xAccess.getRaw(iter) & 0xff) >> (-n)); + } + } else { + while (xAccess.next(iter)) { + data[iter.getIndex()] = (byte) (xAccess.getRaw(iter) << n); + } } + return RDataFactory.createRawVector(data); } - return RDataFactory.createRawVector(data); } - } - - // TODO the rest of the functions + @Specialization(replaces = "rawShift") + @TruffleBoundary + protected RRawVector rawShiftGeneric(RAbstractRawVector x, int n, + @Cached("createBinaryProfile()") ConditionProfile negativeShiftProfile) { + return rawShift(x, n, negativeShiftProfile, x.slowPathAccess()); + } + } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java index 3afe3566f550717f1ebf1ee311c4e129a4659027..dddf8bfadbbfd7e0f40b5cf9b06f63686d688c4f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RawToBits.java @@ -25,6 +25,8 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; @@ -32,6 +34,8 @@ import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; @RBuiltin(name = "rawToBits", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) public abstract class RawToBits extends RBuiltinNode.Arg1 { @@ -41,17 +45,26 @@ public abstract class RawToBits extends RBuiltinNode.Arg1 { casts.arg("x").mustNotBeNull(RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x").mustBe(Predef.rawValue(), RError.Message.ARGUMENT_MUST_BE_RAW_VECTOR, "x"); } - @Specialization - protected RAbstractRawVector rawToBits(RAbstractRawVector x) { - byte[] result = new byte[8 * x.getLength()]; - int pos = 0; - for (int j = 0; j < x.getLength(); j++) { - byte temp = x.getRawDataAt(j); - for (int i = 0; i < 8; i++) { - result[pos++] = (byte) (temp & 1); - temp >>= 1; + @Specialization(guards = "xAccess.supports(x)") + protected RAbstractRawVector rawToBits(RAbstractRawVector x, + @Cached("x.access()") VectorAccess xAccess) { + try (SequentialIterator iter = xAccess.access(x)) { + byte[] result = new byte[8 * x.getLength()]; + int pos = 0; + while (xAccess.next(iter)) { + byte temp = xAccess.getRaw(iter); + for (int i = 0; i < 8; i++) { + result[pos++] = (byte) (temp & 1); + temp >>= 1; + } } + return RDataFactory.createRawVector(result); } - return RDataFactory.createRawVector(result); + } + + @Specialization(replaces = "rawToBits") + @TruffleBoundary + protected RAbstractRawVector rawToBitsGeneric(RAbstractRawVector x) { + return rawToBits(x, x.slowPathAccess()); } }