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 621292af809b246636c5832544e47c4257068b49..ce6a668a1d7d4a1758fe6505bcba8cf22fb26b69 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 @@ -658,8 +658,8 @@ final class REngine implements Engine, Engine.Timings { @TruffleBoundary private static boolean checkResult(Object result) { - if (FastROptions.CheckResultCompleteness.getBooleanValue() && result instanceof RAbstractVector && ((RAbstractVector) result).isComplete()) { - assert ((RAbstractVector) result).checkCompleteness() : "vector: " + result + " is not complete, but isComplete flag is true"; + if (FastROptions.CheckResultCompleteness.getBooleanValue() && result instanceof RAbstractVector) { + assert RAbstractVector.verify((RAbstractVector) result); } return true; } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java index d5efff6efc4373ec4a7162d411aa4f4d9615b327..cab4934525c42ab1be917f7f54f8c255d53f9b3d 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java @@ -90,16 +90,12 @@ import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.RUnboundValue; -import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -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.RAbstractListBaseVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; -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.RandomIterator; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.env.REnvironment.PutException; import com.oracle.truffle.r.runtime.ffi.DLL; @@ -860,138 +856,37 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { @Override @TruffleBoundary public void Rf_copyMatrix(Object t, Object s, int byRow) { - int tRows = RRuntime.nrows(t); - int tCols = RRuntime.ncols(t); - final Object sav = RRuntime.asAbstractVector(s); - ContainerItemCopier c; - if (sav instanceof RAbstractContainer) { - int sLen = ((RAbstractContainer) sav).getLength(); - if (sav instanceof RAbstractIntVector) { - c = new ContainerItemCopier() { - private final RAbstractIntVector sv = (RAbstractIntVector) sav; - private final RAbstractIntVector tv = (RAbstractIntVector) t; - private final Object tvStore = tv.getInternalStore(); - - @Override - public void copy(int sIdx, int tIdx) { - tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); - } - }; - } else if (sav instanceof RAbstractDoubleVector) { - c = new ContainerItemCopier() { - - private final RAbstractDoubleVector sv = (RAbstractDoubleVector) sav; - private final RAbstractDoubleVector tv = (RAbstractDoubleVector) t; - private final Object tvStore = tv.getInternalStore(); - - @Override - public void copy(int sIdx, int tIdx) { - tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); - } - }; - } else if (sav instanceof RAbstractLogicalVector) { - c = new ContainerItemCopier() { - private final RAbstractLogicalVector sv = (RAbstractLogicalVector) sav; - private final RAbstractLogicalVector tv = (RAbstractLogicalVector) t; - private final Object tvStore = tv.getInternalStore(); - - @Override - public void copy(int sIdx, int tIdx) { - tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); - } - }; - } else if (sav instanceof RAbstractComplexVector) { - c = new ContainerItemCopier() { - private final RAbstractComplexVector sv = (RAbstractComplexVector) sav; - private final RAbstractComplexVector tv = (RAbstractComplexVector) t; - private final Object tvStore = tv.getInternalStore(); - - @Override - public void copy(int sIdx, int tIdx) { - tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); - } - }; - } else if (sav instanceof RAbstractStringVector) { - c = new ContainerItemCopier() { - private final RAbstractStringVector sv = (RAbstractStringVector) sav; - private final RAbstractStringVector tv = (RAbstractStringVector) t; - private final Object tvStore = tv.getInternalStore(); - - @Override - public void copy(int sIdx, int tIdx) { - tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); - } - }; - } else if (sav instanceof RAbstractRawVector) { - c = new ContainerItemCopier() { - private final RAbstractRawVector sv = (RAbstractRawVector) sav; - private final RAbstractRawVector tv = (RAbstractRawVector) t; - private final Object tvStore = tv.getInternalStore(); - - @Override - public void copy(int sIdx, int tIdx) { - tv.setRawDataAt(tvStore, tIdx, sv.getRawDataAt(sIdx)); - } - }; - } else if (sav instanceof RAbstractListBaseVector) { - c = new ContainerItemCopier() { - private final RAbstractListBaseVector sv = (RAbstractListBaseVector) sav; - private final RAbstractListBaseVector tv = (RAbstractListBaseVector) t; - private final Object tvStore = tv.getInternalStore(); - - @Override - public void copy(int sIdx, int tIdx) { - tv.setDataAt(tvStore, tIdx, sv.getDataAt(sIdx)); - } - }; - } else { - throw unimplemented(); - } - if (byRow != 0) { - int sIdx = 0; - for (int i = 0; i < tRows; i++) { - int tIdx = i; - for (int j = 0; j < tCols; j++) { - c.copy(sIdx, tIdx); - sIdx++; - if (sIdx >= sLen) { - sIdx -= sLen; + RAbstractVector target = guaranteeInstanceOf(t, RAbstractVector.class); + RAbstractVector source = guaranteeInstanceOf(RRuntime.asAbstractVector(s), RAbstractVector.class); + + VectorAccess targetAccess = target.slowPathAccess(); + VectorAccess sourceAccess = source.slowPathAccess(); + + try (SequentialIterator sourceIter = sourceAccess.access(source)) { + if (byRow != 0) { // copy by row + int tRows = RRuntime.nrows(target); + int tCols = RRuntime.ncols(target); + try (RandomIterator targetIter = targetAccess.randomAccess(target)) { + for (int i = 0; i < tRows; i++) { + int tIdx = i; + for (int j = 0; j < tCols; j++) { + sourceAccess.nextWithWrap(sourceIter); + targetAccess.setFromSameType(targetIter, tIdx, sourceAccess, sourceIter); + tIdx += tRows; } - tIdx += tRows; } } - } else { // Copy by column - int tLen = ((RAbstractContainer) t).getLength(); - if (sLen >= tLen) { - for (int i = 0; i < tLen; i++) { - c.copy(i, i); - } - } else { // Recycle needed - int sIdx = 0; - for (int i = 0; i < tLen; i++) { - c.copy(sIdx, i); - sIdx++; - if (sIdx >= sLen) { - sIdx -= sLen; - } + } else { // copy by column + try (SequentialIterator targetIter = targetAccess.access(target)) { + while (targetAccess.next(targetIter)) { + sourceAccess.nextWithWrap(sourceIter); + targetAccess.setFromSameType(targetIter, sourceAccess, sourceIter); } } } - } else { // source is non-RAbstractContainer - throw unimplemented(); } } - /** - * Helper interface for {@link #Rf_copyMatrix(java.lang.Object, java.lang.Object, int)} that - * copies from source index in an (internally held) source container into target index in a - * target container. - */ - interface ContainerItemCopier { - - void copy(int sIdx, int tIdx); - } - @Override @TruffleBoundary public Object R_tryEval(Object expr, Object env, int silent) { diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java index 9e8c18a8c8da56b9fea99f90ae32870a4102a380..61fa874e2c41ff9556ba9ef288fc7eb4fd5b9d25 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/ListAccessNodes.java @@ -49,7 +49,6 @@ import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypes; -import com.oracle.truffle.r.runtime.data.nodes.GetDataCopy; /** * Nodes that implement {@code CAR}, {@code CDR}, etc. N.B. GNU R does not error check the @@ -170,7 +169,6 @@ public final class ListAccessNodes { @Specialization protected Object cdr(RList list, - @Cached("create()") GetDataCopy.String getDataCopyNode, @Cached("create()") GetNamesAttributeNode getNamesNode, @Cached("create()") SetNamesAttributeNode setNamesNode) { if (list.getLength() == 1) { @@ -179,7 +177,7 @@ public final class ListAccessNodes { RStringVector names = getNamesNode.getNames(list); RList copy = RDataFactory.createList(list.getDataCopy()); if (names != null) { - String[] namesDataCopy = getDataCopyNode.execute(names); + String[] namesDataCopy = names.getDataCopy(); setNamesNode.setNames(copy, RDataFactory.createStringVector(namesDataCopy, true)); } return copy; diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java index 1c6562db6396bdce9c7600220ce3fcbee4ee6afd..c42616fccf5020f685de15630ff0640d6549dfb4 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java @@ -43,7 +43,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetNames import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.SetNamesAttributeNodeGen; import com.oracle.truffle.r.nodes.builtin.EnvironmentNodes.GetFunctionEnvironmentNode; import com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder; -import com.oracle.truffle.r.nodes.builtin.casts.fluent.HeadPhaseBuilder; import com.oracle.truffle.r.nodes.objects.NewObject; import com.oracle.truffle.r.nodes.objects.NewObjectNodeGen; import com.oracle.truffle.r.nodes.unary.CastNode; @@ -57,8 +56,6 @@ import com.oracle.truffle.r.runtime.data.RRawVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.nodes.GetDataAt; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; @@ -266,26 +263,17 @@ public final class MiscNodes { @Specialization protected RRawVector octSize(Object size, @Cached("create()") SizeToOctalRawNode sizeToOctal, - @Cached("createCast()") CastNode castToDoubleNode, - @Cached("create()") GetDataAt.Double getDataNode) { - - Object val = castToDoubleNode.doCast(size); - if (val instanceof RAbstractDoubleVector) { - RAbstractDoubleVector vec = (RAbstractDoubleVector) val; - return sizeToOctal.execute(getDataNode.get(vec, vec.getInternalStore(), 0)); - } - return sizeToOctal.execute(val); + @Cached("createCast()") CastNode castToDoubleNode) { + return sizeToOctal.execute(castToDoubleNode.doCast(size)); } protected CastNode createCast() { - HeadPhaseBuilder<Double> findFirst = CastNodeBuilder.newCastBuilder().mustNotBeMissing().allowNull().asDoubleVector().findFirst(); - return findFirst.buildCastNode(); + return CastNodeBuilder.newCastBuilder().mustNotBeMissing().allowNull().asDoubleVector().findFirst().buildCastNode(); } public static OctSizeNode create() { return OctSizeNodeGen.create(); } } - } diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java index 6c7e397ee82032a85b9aacb020447351289f4de8..2693615f508a0d1ff9bdfd3af494c667e2385d05 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/FFIWrapNode.java @@ -36,6 +36,7 @@ import com.oracle.truffle.r.runtime.data.RLogical; import com.oracle.truffle.r.runtime.data.RObject; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RScalarList; +import com.oracle.truffle.r.runtime.data.RScalarVector; import com.oracle.truffle.r.runtime.data.RSequence; public abstract class FFIWrapNode extends Node { @@ -92,7 +93,11 @@ public abstract class FFIWrapNode extends Node { return wrap(RDataFactory.createComplexVectorFromScalar(value)); } - @Specialization + protected static boolean isRScalarVector(RObject value) { + return value instanceof RScalarVector; + } + + @Specialization(guards = "!isRScalarVector(value)") protected static Object wrap(RObject value) { return value; } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java index 87ac3095c6689f05bc93ba6516e6732797683790..1bdce4fb65e441e2951aeb3a516f2f6457ea8a23 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/DoSetViewPort.java @@ -38,6 +38,7 @@ import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; 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.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; final class DoSetViewPort { @@ -74,7 +75,7 @@ final class DoSetViewPort { pushedViewPort.setDataAt(ViewPort.PVP_DEVWIDTHCM, scalar(Unit.inchesToCm(currentDevice.getWidth()))); pushedViewPort.setDataAt(ViewPort.PVP_DEVHEIGHTCM, scalar(Unit.inchesToCm(currentDevice.getHeight()))); - assert pushedViewPort.verify(); + assert RAbstractVector.verify(pushedViewPort); return pushedViewPort; } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java index c1cfe4461c2f329c6d60fda68c3fe648c2db9791..77f8e4293eab0192390b1f6552f99e863b47a582 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/GridState.java @@ -18,6 +18,7 @@ import com.oracle.truffle.r.library.fastrGrid.device.GridDevice; import com.oracle.truffle.r.library.fastrGrid.grDevices.FileDevUtils; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.REnvironment; public final class GridState { @@ -104,7 +105,7 @@ public final class GridState { public void initGPar(GridDevice currentDevice) { devState.gpar = GPar.createNew(currentDevice); - assert devState.gpar.verify(); + assert RAbstractVector.verify(devState.gpar); } /** @@ -143,7 +144,7 @@ public final class GridState { } public void setViewPort(RList viewPort) { - assert viewPort.verify(); + assert RAbstractVector.verify(viewPort); devState.viewPort = viewPort; } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java index e8051d5c63c0263639650ca2a42699774dc20f65..371fe577b934023e585821fb963aaff0067f9172 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/fastrGrid/grDevices/DevCairo.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.library.fastrGrid.grDevices; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.library.fastrGrid.GridContext; import com.oracle.truffle.r.library.fastrGrid.device.SVGDevice; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; @@ -36,6 +37,7 @@ public class DevCairo extends RExternalBuiltinNode { } @Override + @TruffleBoundary protected Object call(RArgsValuesAndNames args) { if (args.getLength() < 4) { throw error(Message.ARGUMENTS_REQUIRED_COUNT, args.getLength(), "devCairo", 4); diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java index cffbaad71f9c59b41e3cae935605ccf4bf441156..1d88093b56227120073c643e15d546084b029479 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cdist.java @@ -12,9 +12,9 @@ */ package com.oracle.truffle.r.library.stats; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; import static com.oracle.truffle.r.runtime.nmath.MathConstants.DBL_MIN; import com.oracle.truffle.api.dsl.Cached; @@ -25,8 +25,6 @@ import com.oracle.truffle.r.nodes.attributes.SetAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetClassAttributeNode; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; -import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor; -import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RDataFactory; @@ -34,9 +32,12 @@ import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +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.ops.na.NACheck; public abstract class Cdist extends RExternalBuiltinNode.Arg4 { + private static final NACheck naCheck = NACheck.create(); @Child private GetFixedAttributeNode getNamesAttrNode = GetFixedAttributeNode.createNames(); @@ -49,9 +50,10 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { casts.arg(3).asDoubleVector().findFirst(); } - @Specialization(guards = "method == cachedMethod") - protected RDoubleVector cdist(RAbstractDoubleVector x, @SuppressWarnings("unused") int method, RList list, double p, @SuppressWarnings("unused") @Cached("method") int cachedMethod, - @Cached("create()") VectorReadAccess.Double xAccess, + @Specialization(guards = {"method == cachedMethod", "xAccess.supports(x)"}) + protected RDoubleVector cdist(RAbstractDoubleVector x, @SuppressWarnings("unused") int method, RList list, double p, + @Cached("method") @SuppressWarnings("unused") int cachedMethod, + @Cached("x.access()") VectorAccess xAccess, @Cached("getMethod(method)") Method methodObj, @Cached("create()") SetAttributeNode setAttrNode, @Cached("create()") SetClassAttributeNode setClassAttrNode, @@ -60,8 +62,10 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { int nc = getDimNode.ncols(x); int n = nr * (nr - 1) / 2; /* avoid int overflow for N ~ 50,000 */ double[] ans = new double[n]; - RDoubleVector xm = x.materialize(); - rdistance(new ReadAccessor.Double(x, xAccess), nr, nc, ans, false, methodObj, p); + + try (RandomIterator xIter = xAccess.randomAccess(x)) { + rdistance(xAccess, xIter, nr, nc, ans, false, methodObj, p); + } RDoubleVector result = RDataFactory.createDoubleVector(ans, naCheck.neverSeenNA()); DynamicObject resultAttrs = result.initAttributes(); @@ -81,6 +85,14 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { return result; } + @Specialization(replaces = "cdist") + protected RDoubleVector cdistGeneric(RAbstractDoubleVector x, int method, RList list, double p, + @Cached("create()") SetAttributeNode setAttrNode, + @Cached("create()") SetClassAttributeNode setClassAttrNode, + @Cached("create()") GetDimAttributeNode getDimNode) { + return cdist(x, method, list, p, method, x.slowPathAccess(), getMethod(method), setAttrNode, setClassAttrNode, getDimNode); + } + private static boolean bothNonNAN(double a, double b) { return !RRuntime.isNAorNaN(a) && !RRuntime.isNAorNaN(b); } @@ -96,7 +108,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { return Method.values()[method - 1]; } - private void rdistance(ReadAccessor.Double xAccess, int nr, int nc, double[] d, boolean diag, Method method, double p) { + private void rdistance(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, double[] d, boolean diag, Method method, double p) { int ij; /* can exceed 2^31 - 1, but Java can't handle that */ // if (method == Method.MINKOWSKI) { @@ -109,7 +121,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { naCheck.enable(true); for (int j = 0; j <= nr; j++) { for (int i = j + dc; i < nr; i++) { - double r = method.dist(xAccess, nr, nc, i, j, p); + double r = method.dist(xAccess, xIter, nr, nc, i, j, p); naCheck.check(r); d[ij++] = r; } @@ -119,7 +131,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { public enum Method { EUCLIDEAN { @Override - public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) { + public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) { int i1 = i1in; int i2 = i2in; double dev; @@ -130,8 +142,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { count = 0; dist = 0; for (j = 0; j < nc; j++) { - if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) { - dev = (xAccess.getDataAt(i1) - xAccess.getDataAt(i2)); + if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) { + dev = (xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2)); if (!RRuntime.isNAorNaN(dev)) { dist += dev * dev; count++; @@ -152,7 +164,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { }, MAXIMUM { @Override - public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) { + public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) { int i1 = i1in; int i2 = i2in; double dev; @@ -163,8 +175,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { count = 0; dist = -Double.MAX_VALUE; for (j = 0; j < nc; j++) { - if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) { - dev = Math.abs(xAccess.getDataAt(i1) - xAccess.getDataAt(i2)); + if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) { + dev = Math.abs(xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2)); if (!RRuntime.isNAorNaN(dev)) { if (dev > dist) { dist = dev; @@ -184,7 +196,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { }, MANHATTAN { @Override - public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) { + public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) { int i1 = i1in; int i2 = i2in; double dev; @@ -195,8 +207,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { count = 0; dist = 0; for (j = 0; j < nc; j++) { - if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) { - dev = Math.abs(xAccess.getDataAt(i1) - xAccess.getDataAt(i2)); + if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) { + dev = Math.abs(xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2)); if (!RRuntime.isNAorNaN(dev)) { dist += dev; count++; @@ -217,7 +229,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { }, CANBERRA { @Override - public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) { + public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) { int i1 = i1in; int i2 = i2in; double dev; @@ -230,9 +242,9 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { count = 0; dist = 0; for (j = 0; j < nc; j++) { - if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) { - sum = Math.abs(xAccess.getDataAt(i1) + xAccess.getDataAt(i2)); - diff = Math.abs(xAccess.getDataAt(i1) - xAccess.getDataAt(i2)); + if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) { + sum = Math.abs(xAccess.getDouble(xIter, i1) + xAccess.getDouble(xIter, i2)); + diff = Math.abs(xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2)); if (sum > DBL_MIN || diff > DBL_MIN) { dev = diff / sum; if (!RRuntime.isNAorNaN(dev) || @@ -258,7 +270,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { }, BINARY { @Override - public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) { + public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) { int i1 = i1in; int i2 = i2in; int total; @@ -271,13 +283,13 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { dist = 0; for (j = 0; j < nc; j++) { - if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) { - if (!bothFinite(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) { + if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) { + if (!bothFinite(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) { RError.warning(RError.SHOW_CALLER2, RError.Message.GENERIC, "treating non-finite values as NA"); } else { - if (xAccess.getDataAt(i1) != 0. || xAccess.getDataAt(i2) != 0.) { + if (xAccess.getDouble(xIter, i1) != 0. || xAccess.getDouble(xIter, i2) != 0.) { count++; - if (!(xAccess.getDataAt(i1) != 0. && xAccess.getDataAt(i2) != 0.)) { + if (!(xAccess.getDouble(xIter, i1) != 0. && xAccess.getDouble(xIter, i2) != 0.)) { dist++; } } @@ -300,7 +312,7 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { }, MINKOWSKI { @Override - public double dist(ReadAccessor.Double xAccess, int nr, int nc, final int i1in, final int i2in, double p) { + public double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, final int i1in, final int i2in, double p) { int i1 = i1in; int i2 = i2in; double dev; @@ -311,8 +323,8 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { count = 0; dist = 0; for (j = 0; j < nc; j++) { - if (bothNonNAN(xAccess.getDataAt(i1), xAccess.getDataAt(i2))) { - dev = (xAccess.getDataAt(i1) - xAccess.getDataAt(i2)); + if (bothNonNAN(xAccess.getDouble(xIter, i1), xAccess.getDouble(xIter, i2))) { + dev = (xAccess.getDouble(xIter, i1) - xAccess.getDouble(xIter, i2)); if (!RRuntime.isNAorNaN(dev)) { dist += Math.pow(Math.abs(dev), p); count++; @@ -331,6 +343,6 @@ public abstract class Cdist extends RExternalBuiltinNode.Arg4 { } }; - public abstract double dist(ReadAccessor.Double xAccess, int nr, int nc, int i1, int i2, double p); + public abstract double dist(VectorAccess xAccess, RandomIterator xIter, int nr, int nc, int i1, int i2, double p); } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java index 0a07a8b78c67ee7965a500d2cb61c1561e9feffc..8c0052139f253fd4233b127aeefe7f0cedaeb1df 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Cutree.java @@ -20,7 +20,8 @@ import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; -import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; // translated from library/stats/src/hclust_utils.c @@ -32,10 +33,10 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 { casts.arg(1).mustNotBeMissing().mapIf(nullValue(), emptyIntegerVector()).asIntegerVector(); } - @Specialization + @Specialization(guards = {"mergeAccess.supports(merge)", "whichAccess.supports(which)"}) protected RIntVector cutree(RAbstractIntVector merge, RAbstractIntVector which, - @Cached("create()") VectorReadAccess.Int mergeAccess, - @Cached("create()") VectorReadAccess.Int whichAccess, + @Cached("merge.access()") VectorAccess mergeAccess, + @Cached("which.access()") VectorAccess whichAccess, @Cached("create()") GetDimAttributeNode getDimNode) { int whichLen = which.getLength(); @@ -59,92 +60,96 @@ public abstract class Cutree extends RExternalBuiltinNode.Arg2 { int[] z = new int[n]; int[] iAns = new int[n * whichLen]; - Object mergeStore = mergeAccess.getDataStore(merge); - Object whichStore = whichAccess.getDataStore(which); + try (RandomIterator mergeIter = mergeAccess.randomAccess(merge); RandomIterator whichIter = whichAccess.randomAccess(which)) { - // for (k = 1; k <= n; k++) { - for (k = 0; k < n; k++) { - sing[k] = true; /* is k-th obs. still alone in cluster ? */ - mNr[k] = 0; /* containing last merge-step number of k-th obs. */ - } + // for (k = 1; k <= n; k++) { + for (k = 0; k < n; k++) { + sing[k] = true; /* is k-th obs. still alone in cluster ? */ + mNr[k] = 0; /* containing last merge-step number of k-th obs. */ + } - for (k = 1; k <= n - 1; k++) { - /* k-th merge, from n-k+1 to n-k atoms: (m1,m2) = merge[ k , ] */ - m1 = mergeAccess.getDataAt(merge, mergeStore, k - 1); - m2 = mergeAccess.getDataAt(merge, mergeStore, n - 1 + k - 1); - - if (m1 < 0 && m2 < 0) { /* merging atoms [-m1] and [-m2] */ - mNr[adj(-m1)] = mNr[adj(-m2)] = k; - sing[adj(-m1)] = sing[adj(-m2)] = false; - } else if (m1 < 0 || m2 < 0) { /* the other >= 0 */ - if (m1 < 0) { - j = -m1; - m1 = m2; - } else { - j = -m2; - } - /* merging atom j & cluster m1 */ - for (l = 1; l <= n; l++) { - if (mNr[adj(l)] == m1) { - mNr[adj(l)] = k; + for (k = 1; k <= n - 1; k++) { + /* k-th merge, from n-k+1 to n-k atoms: (m1,m2) = merge[ k , ] */ + m1 = mergeAccess.getInt(mergeIter, k - 1); + m2 = mergeAccess.getInt(mergeIter, n - 1 + k - 1); + + if (m1 < 0 && m2 < 0) { /* merging atoms [-m1] and [-m2] */ + mNr[adj(-m1)] = mNr[adj(-m2)] = k; + sing[adj(-m1)] = sing[adj(-m2)] = false; + } else if (m1 < 0 || m2 < 0) { /* the other >= 0 */ + if (m1 < 0) { + j = -m1; + m1 = m2; + } else { + j = -m2; } - } - mNr[adj(j)] = k; - sing[adj(j)] = false; - } else { /* both m1, m2 >= 0 */ - for (l = 1; l <= n; l++) { - if (mNr[adj(l)] == m1 || mNr[adj(l)] == m2) { - mNr[adj(l)] = k; + /* merging atom j & cluster m1 */ + for (l = 1; l <= n; l++) { + if (mNr[adj(l)] == m1) { + mNr[adj(l)] = k; + } + } + mNr[adj(j)] = k; + sing[adj(j)] = false; + } else { /* both m1, m2 >= 0 */ + for (l = 1; l <= n; l++) { + if (mNr[adj(l)] == m1 || mNr[adj(l)] == m2) { + mNr[adj(l)] = k; + } } } - } - /* - * does this k-th merge belong to a desired group size which[j] ? if yes, find j (maybe - * multiple ones): - */ - foundJ = false; - for (j = 0; j < whichLen; j++) { - if (whichAccess.getDataAt(which, whichStore, j) == n - k) { - if (!foundJ) { /* first match (and usually only one) */ - foundJ = true; - // for (l = 1; l <= n; l++) - for (l = 0; l < n; l++) { - z[l] = 0; - } - nclust = 0; - mm = j * n; /* may want to copy this column of ans[] */ - for (l = 1, m1 = mm; l <= n; l++, m1++) { - if (sing[adj(l)]) { - iAns[m1] = ++nclust; - } else { - if (z[adj(mNr[adj(l)])] == 0) { - z[adj(mNr[adj(l)])] = ++nclust; + /* + * does this k-th merge belong to a desired group size which[j] ? if yes, find j + * (maybe multiple ones): + */ + foundJ = false; + for (j = 0; j < whichLen; j++) { + if (whichAccess.getInt(whichIter, j) == n - k) { + if (!foundJ) { /* first match (and usually only one) */ + foundJ = true; + // for (l = 1; l <= n; l++) + for (l = 0; l < n; l++) { + z[l] = 0; + } + nclust = 0; + mm = j * n; /* may want to copy this column of ans[] */ + for (l = 1, m1 = mm; l <= n; l++, m1++) { + if (sing[adj(l)]) { + iAns[m1] = ++nclust; + } else { + if (z[adj(mNr[adj(l)])] == 0) { + z[adj(mNr[adj(l)])] = ++nclust; + } + iAns[m1] = z[adj(mNr[adj(l)])]; } - iAns[m1] = z[adj(mNr[adj(l)])]; + } + } else { /* found_j: another which[j] == n-k : copy column */ + for (l = 1, m1 = j * n, m2 = mm; l <= n; l++, m1++, m2++) { + iAns[m1] = iAns[m2]; } } - } else { /* found_j: another which[j] == n-k : copy column */ - for (l = 1, m1 = j * n, m2 = mm; l <= n; l++, m1++, m2++) { - iAns[m1] = iAns[m2]; - } + } /* if ( match ) */ + } /* for(j .. which[j] ) */ + } /* for(k ..) {merge} */ + + /* Dealing with trivial case which[] = n : */ + for (j = 0; j < whichLen; j++) { + if (whichAccess.getInt(whichIter, j) == n) { + for (l = 1, m1 = j * n; l <= n; l++, m1++) { + iAns[m1] = l; } - } /* if ( match ) */ - } /* for(j .. which[j] ) */ - } /* for(k ..) {merge} */ - - /* Dealing with trivial case which[] = n : */ - for (j = 0; j < whichLen; j++) { - if (whichAccess.getDataAt(which, whichStore, j) == n) { - for (l = 1, m1 = j * n; l <= n; l++, m1++) { - iAns[m1] = l; } } } - RIntVector result = RDataFactory.createIntVector(iAns, RDataFactory.COMPLETE_VECTOR, new int[]{n, whichLen}); - return result; + return RDataFactory.createIntVector(iAns, RDataFactory.COMPLETE_VECTOR, new int[]{n, whichLen}); + } + @Specialization(replaces = "cutree") + protected RIntVector cutreeGeneric(RAbstractIntVector merge, RAbstractIntVector which, + @Cached("create()") GetDimAttributeNode getDimNode) { + return cutree(merge, which, merge.slowPathAccess(), which.slowPathAccess(), getDimNode); } private static int adj(int i) { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java index 62883376e19d6cccdc6e3ab014c7765086f15e4e..a817389e28340b1a2cca0112feefc0260960de6f 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/DoubleCentre.java @@ -10,56 +10,63 @@ */ package com.oracle.truffle.r.library.stats; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; - import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.nodes.SetDataAt; -import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess; +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.VectorReuse; public abstract class DoubleCentre extends RExternalBuiltinNode.Arg1 { static { Casts casts = new Casts(DoubleCentre.class); - casts.arg(0).mustBe(missingValue().not()).mustBe(nullValue().not(), RError.Message.MACRO_CAN_BE_APPLIED_TO, "REAL()", "numeric", "NULL").asDoubleVector(); + casts.arg(0).mustNotBeNull(RError.Message.MACRO_CAN_BE_APPLIED_TO, "REAL()", "numeric", "NULL").mustNotBeMissing().asDoubleVector(); } - @Specialization - protected RDoubleVector doubleCentre(RAbstractDoubleVector aVecAbs, - @Cached("create()") VectorReadAccess.Double aAccess, - @Cached("create()") SetDataAt.Double aSetter, + @Specialization(guards = {"aAccess.supports(a)", "reuse.supports(a)"}) + protected RAbstractDoubleVector doubleCentre(RAbstractDoubleVector a, + @Cached("a.access()") VectorAccess aAccess, + @Cached("createNonShared(a)") VectorReuse reuse, @Cached("create()") GetDimAttributeNode getDimNode) { - RDoubleVector aVec = aVecAbs.materialize(); - int n = getDimNode.nrows(aVec); - Object aStore = aAccess.getDataStore(aVec); - for (int i = 0; i < n; i++) { - double sum = 0; - for (int j = 0; j < n; j++) { - sum += aAccess.getDataAt(aVec, aStore, i + j * n); - } - sum /= n; - for (int j = 0; j < n; j++) { - double val = aAccess.getDataAt(aVec, aStore, i + j * n); - aSetter.setDataAt(aVec, aStore, i + j * n, val - sum); - } - } - for (int j = 0; j < n; j++) { - double sum = 0; - for (int i = 0; i < n; i++) { - sum += aAccess.getDataAt(aVec, aStore, i + j * n); - } - sum /= n; - for (int i = 0; i < n; i++) { - double val = aAccess.getDataAt(aVec, aStore, i + j * n); - aSetter.setDataAt(aVec, aStore, i + j * n, val - sum); + int n = getDimNode.nrows(a); + + try (RandomIterator aIter = aAccess.randomAccess(a)) { + RAbstractDoubleVector result = reuse.getResult(a); + VectorAccess resultAccess = reuse.access(result); + try (RandomIterator resultIter = resultAccess.randomAccess(result)) { + for (int i = 0; i < n; i++) { + double sum = 0; + for (int j = 0; j < n; j++) { + sum += aAccess.getDouble(aIter, i + j * n); + } + sum /= n; + for (int j = 0; j < n; j++) { + resultAccess.setDouble(resultIter, i + j * n, aAccess.getDouble(aIter, i + j * n) - sum); + } + } + for (int j = 0; j < n; j++) { + double sum = 0; + for (int i = 0; i < n; i++) { + sum += resultAccess.getDouble(aIter, i + j * n); + } + sum /= n; + for (int i = 0; i < n; i++) { + resultAccess.setDouble(resultIter, i + j * n, resultAccess.getDouble(aIter, i + j * n) - sum); + } + } } + return result; } - return aVec; + } + + @Specialization(replaces = "doubleCentre") + protected RAbstractDoubleVector doubleCentreGeneric(RAbstractDoubleVector a, + @Cached("createNonSharedGeneric()") VectorReuse reuse, + @Cached("create()") GetDimAttributeNode getDimNode) { + return doubleCentre(a, a.slowPathAccess(), reuse, getDimNode); } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java index 56fa2752f569d2701e8f2239d05775022b239357..0fcd70396e68153561ab018f2ac36a6f3b5083e1 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RMultinomNode.java @@ -27,18 +27,15 @@ import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode; import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; -import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode; import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.RIntVector; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor; -import com.oracle.truffle.r.runtime.data.nodes.SetDataAt; -import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess; +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.nmath.RandomFunctions.RandomNumberProvider; import com.oracle.truffle.r.runtime.nmath.distr.RMultinom; import com.oracle.truffle.r.runtime.nmath.distr.Rbinom; @@ -49,8 +46,15 @@ import com.oracle.truffle.r.runtime.rng.RRNG; * Implements the vectorization of {@link RMultinom}. */ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 { + private final Rbinom rbinom = new Rbinom(); + private final ValueProfile randGeneratorClassProfile = ValueProfile.createClassProfile(); + private final ConditionProfile hasAttributesProfile = ConditionProfile.createBinaryProfile(); + @Child private UpdateShareableChildValueNode updateSharedAttributeNode = UpdateShareableChildValueNode.create(); + @Child private GetFixedAttributeNode getNamesNode = GetFixedAttributeNode.createNames(); + @Child private SetFixedAttributeNode setDimNamesNode = SetFixedAttributeNode.createDimNames(); + public static RMultinomNode create() { return RMultinomNodeGen.create(); } @@ -68,63 +72,69 @@ public abstract class RMultinomNode extends RExternalBuiltinNode.Arg3 { } @Specialization - protected RIntVector doMultinom(int n, int size, RAbstractDoubleVector probsVec, - @Cached("create()") VectorReadAccess.Double probsAccess, - @Cached("create()") SetDataAt.Double probsSetter, - @Cached("create()") ReuseNonSharedNode reuseNonSharedNode, - @Cached("createClassProfile()") ValueProfile randGeneratorClassProfile, - @Cached("createBinaryProfile()") ConditionProfile hasAttributesProfile, - @Cached("create()") UpdateShareableChildValueNode updateSharedAttributeNode, - @Cached("createNames()") GetFixedAttributeNode getNamesNode, - @Cached("createDimNames()") SetFixedAttributeNode setDimNamesNode) { - RDoubleVector nonSharedProbs = ((RAbstractDoubleVector) reuseNonSharedNode.execute(probsVec)).materialize(); - ReadAccessor.Double probs = new ReadAccessor.Double(nonSharedProbs, probsAccess); - fixupProb(nonSharedProbs, probs, probsSetter); - - RRNG.getRNGState(); - RandomNumberProvider rand = new RandomNumberProvider(randGeneratorClassProfile.profile(RRNG.currentGenerator()), RRNG.currentNormKind()); - int k = nonSharedProbs.getLength(); - int[] result = new int[k * n]; - boolean isComplete = true; - for (int i = 0, ik = 0; i < n; i++, ik += k) { - isComplete &= RMultinom.rmultinom(size, probs, k, result, ik, rand, rbinom); - } - RRNG.putRNGState(); + protected RIntVector doMultinom(int n, int size, RAbstractDoubleVector probs, + @Cached("probs.access()") VectorAccess probsAccess) { + try (SequentialIterator probsIter = probsAccess.access(probs)) { + double sum = 0.0; + while (probsAccess.next(probsIter)) { + double prob = probsAccess.getDouble(probsIter); + if (!Double.isFinite(prob)) { + throw error(NA_IN_PROB_VECTOR); + } + if (prob < 0.0) { + throw error(NEGATIVE_PROBABILITY); + } + sum += prob; + } + if (sum == 0) { + throw error(NO_POSITIVE_PROBABILITIES); + } - // take names from probVec (if any) as row names in the result - RIntVector resultVec = RDataFactory.createIntVector(result, isComplete, new int[]{k, n}); - if (hasAttributesProfile.profile(probsVec.getAttributes() != null)) { - Object probsNames = getNamesNode.execute(probsVec.getAttributes()); - updateSharedAttributeNode.execute(probsVec, probsNames); - Object[] dimnamesData = new Object[]{probsNames, RNull.instance}; - setDimNamesNode.execute(resultVec.getAttributes(), RDataFactory.createList(dimnamesData)); - } - return resultVec; - } + RRNG.getRNGState(); + RandomNumberProvider rand = new RandomNumberProvider(randGeneratorClassProfile.profile(RRNG.currentGenerator()), RRNG.currentNormKind()); + int[] result = new int[probsAccess.getLength(probsIter) * n]; + if (size > 0) { + for (int i = 0, ik = 0; i < n; i++, ik += probsAccess.getLength(probsIter)) { + double currentSum = sum; + int currentSize = size; + /* Generate the first K-1 obs. via binomials */ + probsAccess.reset(probsIter); + for (int k = 0; probsAccess.next(probsIter) && k < probsAccess.getLength(probsIter) - 1; k++) { + /* (p_tot, n) are for "remaining binomial" */ + /* LDOUBLE */double probK = probsAccess.getDouble(probsIter); + if (probK != 0.) { + double pp = probK / currentSum; + int value = (pp < 1.) ? (int) rbinom.execute(currentSize, pp, rand) : currentSize; + /* + * >= 1; > 1 happens because of rounding + */ + result[ik + k] = value; + currentSize -= value; + } else { + result[ik + k] = 0; + } + if (n <= 0) { + /* we have all */ + break; + } + /* i.e. = sum(prob[(k+1):K]) */ + currentSum -= probK; + } - private void fixupProb(RDoubleVector p, ReadAccessor.Double pAccess, SetDataAt.Double pSetter) { - double sum = 0.0; - int npos = 0; - int pLength = p.getLength(); - for (int i = 0; i < pLength; i++) { - double prob = pAccess.getDataAt(i); - if (!Double.isFinite(prob)) { - throw error(NA_IN_PROB_VECTOR); + result[ik + probsAccess.getLength(probsIter) - 1] = currentSize; + } } - if (prob < 0.0) { - throw error(NEGATIVE_PROBABILITY); - } - if (prob > 0.0) { - npos++; - sum += prob; + RRNG.putRNGState(); + + // take names from probVec (if any) as row names in the result + RIntVector resultVec = RDataFactory.createIntVector(result, true, new int[]{probsAccess.getLength(probsIter), n}); + if (hasAttributesProfile.profile(probs.getAttributes() != null)) { + Object probsNames = getNamesNode.execute(probs.getAttributes()); + updateSharedAttributeNode.execute(probs, probsNames); + Object[] dimnamesData = new Object[]{probsNames, RNull.instance}; + setDimNamesNode.execute(resultVec.getAttributes(), RDataFactory.createList(dimnamesData)); } - } - if (npos == 0) { - throw error(NO_POSITIVE_PROBABILITIES); - } - for (int i = 0; i < pLength; i++) { - double prob = pAccess.getDataAt(i); - pSetter.setDataAt(p, pAccess.getStore(), i, prob / sum); + return resultVec; } } } diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java index f8b8ad866ba0f07df2f543055be4ad89d74ca373..e40046305732232a588eeecfb36dea7c2b6402ee 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandFunctionsNodes.java @@ -16,12 +16,13 @@ package com.oracle.truffle.r.library.stats; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; -import static com.oracle.truffle.r.runtime.RError.Message.INVALID_UNNAMED_ARGUMENTS; import static com.oracle.truffle.r.runtime.RError.SHOW_CALLER; +import static com.oracle.truffle.r.runtime.RError.Message.INVALID_UNNAMED_ARGUMENTS; import java.util.Arrays; +import java.util.function.Function; +import java.util.function.Supplier; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; @@ -31,19 +32,22 @@ import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.ConvertToLen import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction1NodeGen; import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction2NodeGen; import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunction3NodeGen; +import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen; +import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunctionExecutorBaseNodeGen; +import com.oracle.truffle.r.library.stats.RandFunctionsNodesFactory.RandFunctionIntExecutorNodeGen; import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts; import com.oracle.truffle.r.nodes.builtin.RExternalBuiltinNode; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.nodes.unary.CastIntegerNode; import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDouble; 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.RAbstractVector; -import com.oracle.truffle.r.runtime.data.nodes.VectorIterator; +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.nmath.RandomFunctions.RandFunction1_Double; import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction2_Double; import com.oracle.truffle.r.runtime.nmath.RandomFunctions.RandFunction3_Double; @@ -57,7 +61,7 @@ import com.oracle.truffle.r.runtime.rng.RRNG; * {@link RandFunction3_Double}, {@link RandFunction2_Double} or {@link RandFunction1_Double}. */ public final class RandFunctionsNodes { - @CompilationFinal private static final RDouble DUMMY_VECTOR = RDouble.valueOf(1); + private static final RDouble DUMMY_VECTOR = RDouble.valueOf(1); private RandFunctionsNodes() { // static class @@ -101,53 +105,65 @@ public final class RandFunctionsNodes { * {@link RandFunction3_Double}. */ protected abstract static class RandFunctionExecutorBase extends RBaseNode { - static final class RandGenerationNodeData { - final BranchProfile nanResult = BranchProfile.create(); - final BranchProfile nan = BranchProfile.create(); - final VectorLengthProfile resultVectorLengthProfile = VectorLengthProfile.create(); - final LoopConditionProfile loopConditionProfile = LoopConditionProfile.createCountingProfile(); - - public static RandGenerationNodeData create() { - return new RandGenerationNodeData(); - } + + protected final Function<Supplier<? extends RandFunction3_Double>, RandFunctionIterator> iteratorFactory; + protected final Supplier<? extends RandFunction3_Double> functionFactory; + + protected RandFunctionExecutorBase(Function<Supplier<? extends RandFunction3_Double>, RandFunctionIterator> iteratorFactory, Supplier<? extends RandFunction3_Double> functionFactory) { + this.iteratorFactory = iteratorFactory; + this.functionFactory = functionFactory; } + public abstract RAbstractVector execute(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand); + + @Child private ConvertToLength convertToLength = ConvertToLengthNodeGen.create(); + private final VectorLengthProfile resultVectorLengthProfile = VectorLengthProfile.create(); + @Override - protected RBaseNode getErrorContext() { + protected final RBaseNode getErrorContext() { return RError.SHOW_CALLER; } - public abstract Object execute(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand); - - @Child private ConvertToLength convertToLength = ConvertToLengthNodeGen.create(); + protected final RandFunctionIterator createIterator() { + return iteratorFactory.apply(functionFactory); + } @Specialization(guards = {"randCached.isSame(rand)"}) - protected final Object evaluateWithCached(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, + protected final RAbstractVector evaluateWithCached(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, @SuppressWarnings("unused") RandomNumberProvider rand, @Cached("rand") RandomNumberProvider randCached, - @Cached("create()") RandGenerationNodeData nodeData) { - return evaluateWrapper(lengthVec, a, b, c, randCached, nodeData); + @Cached("createIterator()") RandFunctionIterator iterator) { + int length = resultVectorLengthProfile.profile(convertToLength.execute(lengthVec)); + RBaseNode.reportWork(this, length); + return iterator.execute(length, a, b, c, randCached); } @Specialization(replaces = "evaluateWithCached") - protected final Object evaluateFallback(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand, - @Cached("create()") RandGenerationNodeData nodeData) { - return evaluateWrapper(lengthVec, a, b, c, rand, nodeData); + protected final RAbstractVector evaluateFallback(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand, + @Cached("createIterator()") RandFunctionIterator iterator) { + int length = resultVectorLengthProfile.profile(convertToLength.execute(lengthVec)); + RBaseNode.reportWork(this, length); + return iterator.execute(length, a, b, c, rand); } + } - private Object evaluateWrapper(RAbstractVector lengthVec, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand, - RandGenerationNodeData nodeData) { - int length = nodeData.resultVectorLengthProfile.profile(convertToLength.execute(lengthVec)); - RBaseNode.reportWork(this, length); - return evaluate(length, a, b, c, nodeData, rand); + protected abstract static class RandFunctionIterator extends RBaseNode { + + protected final Supplier<? extends RandFunction3_Double> functionFactory; + protected final BranchProfile nanResult = BranchProfile.create(); + protected final BranchProfile nan = BranchProfile.create(); + protected final LoopConditionProfile loopConditionProfile = LoopConditionProfile.createCountingProfile(); + + protected RandFunctionIterator(Supplier<? extends RandFunction3_Double> functionFactory) { + this.functionFactory = functionFactory; } - @SuppressWarnings("unused") - Object evaluate(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandGenerationNodeData nodeData, RandomNumberProvider randProvider) { - // DSL generates code for this class too, with abstract method it would not compile - throw RInternalError.shouldNotReachHere("must be overridden"); + protected final RandFunction3_Double createFunction() { + return functionFactory.get(); } + public abstract RAbstractVector execute(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider rand); + static void putRNGState() { // Note: we call putRNGState only if we actually changed the state, i.e. called random // number generation. We do not need to getRNGState() because the parent wrapper node @@ -160,105 +176,107 @@ public final class RandFunctionsNodes { } } - protected abstract static class RandFunctionIntExecutorNode extends RandFunctionExecutorBase { - @Child private RandFunction3_Double function; - @Child private VectorIterator.Double aIterator = VectorIterator.Double.createWrapAround(); - @Child private VectorIterator.Double bIterator = VectorIterator.Double.createWrapAround(); - @Child private VectorIterator.Double cIterator = VectorIterator.Double.createWrapAround(); + protected abstract static class RandFunctionIntExecutorNode extends RandFunctionIterator { - protected RandFunctionIntExecutorNode(RandFunction3_Double function) { - this.function = function; + protected RandFunctionIntExecutorNode(Supplier<? extends RandFunction3_Double> functionFactory) { + super(functionFactory); } - @Override - protected RAbstractIntVector evaluate(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandGenerationNodeData nodeData, - RandomNumberProvider randProvider) { - int aLength = a.getLength(); - int bLength = b.getLength(); - int cLength = c.getLength(); - if (aLength == 0 || bLength == 0 || cLength == 0) { - nodeData.nanResult.enter(); - showNAWarning(); - int[] nansResult = new int[length]; - Arrays.fill(nansResult, RRuntime.INT_NA); - return RDataFactory.createIntVector(nansResult, false); - } + @Specialization(guards = {"aAccess.supports(a)", "bAccess.supports(b)", "cAccess.supports(c)"}) + protected RAbstractIntVector cached(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider randProvider, + @Cached("createFunction()") RandFunction3_Double function, + @Cached("a.access()") VectorAccess aAccess, + @Cached("b.access()") VectorAccess bAccess, + @Cached("c.access()") VectorAccess cAccess) { + try (SequentialIterator aIter = aAccess.access(a); SequentialIterator bIter = bAccess.access(b); SequentialIterator cIter = cAccess.access(c)) { + if (aAccess.getLength(aIter) == 0 || bAccess.getLength(bIter) == 0 || cAccess.getLength(cIter) == 0) { + nanResult.enter(); + showNAWarning(); + int[] nansResult = new int[length]; + Arrays.fill(nansResult, RRuntime.INT_NA); + return RDataFactory.createIntVector(nansResult, false); + } - Object aIt = aIterator.init(a); - Object bIt = bIterator.init(b); - Object cIt = cIterator.init(c); - boolean nans = false; - int[] result = new int[length]; - nodeData.loopConditionProfile.profileCounted(length); - for (int i = 0; nodeData.loopConditionProfile.inject(i < length); i++) { - double aValue = aIterator.next(a, aIt); - double bValue = bIterator.next(b, bIt); - double cValue = cIterator.next(c, cIt); - double value = function.execute(aValue, bValue, cValue, randProvider); - if (Double.isNaN(value) || value <= Integer.MIN_VALUE || value > Integer.MAX_VALUE) { - nodeData.nan.enter(); - nans = true; - result[i] = RRuntime.INT_NA; - } else { - result[i] = (int) value; + boolean nans = false; + int[] result = new int[length]; + loopConditionProfile.profileCounted(length); + for (int i = 0; loopConditionProfile.inject(i < length); i++) { + aAccess.nextWithWrap(aIter); + bAccess.nextWithWrap(bIter); + cAccess.nextWithWrap(cIter); + double value = function.execute(aAccess.getDouble(aIter), bAccess.getDouble(bIter), cAccess.getDouble(cIter), randProvider); + if (Double.isNaN(value) || value <= Integer.MIN_VALUE || value > Integer.MAX_VALUE) { + nan.enter(); + nans = true; + result[i] = RRuntime.INT_NA; + } else { + result[i] = (int) value; + } } + putRNGState(); + if (nans) { + showNAWarning(); + } + return RDataFactory.createIntVector(result, !nans); } - putRNGState(); - if (nans) { - showNAWarning(); - } - return RDataFactory.createIntVector(result, !nans); + } + + @Specialization(replaces = "cached") + protected RAbstractIntVector generic(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider randProvider, + @Cached("createFunction()") RandFunction3_Double function) { + return cached(length, a, b, c, randProvider, function, a.slowPathAccess(), b.slowPathAccess(), c.slowPathAccess()); } } - protected abstract static class RandFunctionDoubleExecutorNode extends RandFunctionExecutorBase { - @Child private RandFunction3_Double function; - @Child private VectorIterator.Double aIterator = VectorIterator.Double.createWrapAround(); - @Child private VectorIterator.Double bIterator = VectorIterator.Double.createWrapAround(); - @Child private VectorIterator.Double cIterator = VectorIterator.Double.createWrapAround(); + protected abstract static class RandFunctionDoubleExecutorNode extends RandFunctionIterator { - protected RandFunctionDoubleExecutorNode(RandFunction3_Double function) { - this.function = function; + protected RandFunctionDoubleExecutorNode(Supplier<? extends RandFunction3_Double> functionFactory) { + super(functionFactory); } - @Override - protected RAbstractDoubleVector evaluate(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandGenerationNodeData nodeData, - RandomNumberProvider randProvider) { - int aLength = a.getLength(); - int bLength = b.getLength(); - int cLength = c.getLength(); - if (aLength == 0 || bLength == 0 || cLength == 0) { - nodeData.nanResult.enter(); - showNAWarning(); - double[] nansResult = new double[length]; - Arrays.fill(nansResult, RRuntime.DOUBLE_NA); - return RDataFactory.createDoubleVector(nansResult, false); - } + @Specialization(guards = {"aAccess.supports(a)", "bAccess.supports(b)", "cAccess.supports(c)"}) + protected RAbstractDoubleVector cached(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider randProvider, + @Cached("createFunction()") RandFunction3_Double function, + @Cached("a.access()") VectorAccess aAccess, + @Cached("b.access()") VectorAccess bAccess, + @Cached("c.access()") VectorAccess cAccess) { + try (SequentialIterator aIter = aAccess.access(a); SequentialIterator bIter = bAccess.access(b); SequentialIterator cIter = cAccess.access(c)) { + if (aAccess.getLength(aIter) == 0 || bAccess.getLength(bIter) == 0 || cAccess.getLength(cIter) == 0) { + nanResult.enter(); + showNAWarning(); + double[] nansResult = new double[length]; + Arrays.fill(nansResult, RRuntime.DOUBLE_NA); + return RDataFactory.createDoubleVector(nansResult, false); + } - Object aIt = aIterator.init(a); - Object bIt = bIterator.init(b); - Object cIt = cIterator.init(c); - boolean nans = false; - double[] result; - result = new double[length]; - nodeData.loopConditionProfile.profileCounted(length); - for (int i = 0; nodeData.loopConditionProfile.inject(i < length); i++) { - double aValue = aIterator.next(a, aIt); - double bValue = bIterator.next(b, bIt); - double cValue = cIterator.next(c, cIt); - double value = function.execute(aValue, bValue, cValue, randProvider); - if (Double.isNaN(value) || RRuntime.isNA(value)) { - nodeData.nan.enter(); - nans = true; + boolean nans = false; + double[] result = new double[length]; + loopConditionProfile.profileCounted(length); + for (int i = 0; loopConditionProfile.inject(i < length); i++) { + aAccess.nextWithWrap(aIter); + bAccess.nextWithWrap(bIter); + cAccess.nextWithWrap(cIter); + double value = function.execute(aAccess.getDouble(aIter), bAccess.getDouble(bIter), cAccess.getDouble(cIter), randProvider); + if (Double.isNaN(value) || RRuntime.isNA(value)) { + nan.enter(); + nans = true; + } + result[i] = value; } - result[i] = value; - } - putRNGState(); - if (nans) { - showNAWarning(); + putRNGState(); + if (nans) { + showNAWarning(); + } + return RDataFactory.createDoubleVector(result, !nans); } - return RDataFactory.createDoubleVector(result, !nans); } + + @Specialization(replaces = "cached") + protected RAbstractDoubleVector generic(int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c, RandomNumberProvider randProvider, + @Cached("createFunction()") RandFunction3_Double function) { + return cached(length, a, b, c, randProvider, function, a.slowPathAccess(), b.slowPathAccess(), c.slowPathAccess()); + } + } public abstract static class RandFunction3Node extends RExternalBuiltinNode.Arg4 { @@ -268,13 +286,13 @@ public final class RandFunctionsNodes { this.inner = inner; } - public static RandFunction3Node createInt(RandFunction3_Double function) { - return RandFunction3NodeGen.create(RandFunctionsNodesFactory.RandFunctionIntExecutorNodeGen.create(function)); + public static RandFunction3Node createInt(Supplier<RandFunction3_Double> function) { + return RandFunction3NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionIntExecutorNodeGen::create, function)); } // Note: for completeness of the API - public static RandFunction3Node createDouble(RandFunction3_Double function) { - return RandFunction3NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function)); + public static RandFunction3Node createDouble(Supplier<RandFunction3_Double> function) { + return RandFunction3NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionDoubleExecutorNodeGen::create, function)); } static { @@ -286,7 +304,7 @@ public final class RandFunctionsNodes { } @Specialization - protected Object evaluate(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c) { + protected RAbstractVector evaluate(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c) { RRNG.getRNGState(); return inner.execute(length, a, b, c, RandomNumberProvider.fromCurrentRNG()); } @@ -299,12 +317,12 @@ public final class RandFunctionsNodes { this.inner = inner; } - public static RandFunction2Node createInt(RandFunction2_Double function) { - return RandFunction2NodeGen.create(RandFunctionsNodesFactory.RandFunctionIntExecutorNodeGen.create(function)); + public static RandFunction2Node createInt(Supplier<RandFunction2_Double> function) { + return RandFunction2NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionIntExecutorNodeGen::create, function)); } - public static RandFunction2Node createDouble(RandFunction2_Double function) { - return RandFunction2NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function)); + public static RandFunction2Node createDouble(Supplier<RandFunction2_Double> function) { + return RandFunction2NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionDoubleExecutorNodeGen::create, function)); } static { @@ -328,12 +346,12 @@ public final class RandFunctionsNodes { this.inner = inner; } - public static RandFunction1Node createInt(RandFunction1_Double function) { - return RandFunction1NodeGen.create(RandFunctionsNodesFactory.RandFunctionIntExecutorNodeGen.create(function)); + public static RandFunction1Node createInt(Supplier<RandFunction1_Double> function) { + return RandFunction1NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionIntExecutorNodeGen::create, function)); } - public static RandFunction1Node createDouble(RandFunction1_Double function) { - return RandFunction1NodeGen.create(RandFunctionsNodesFactory.RandFunctionDoubleExecutorNodeGen.create(function)); + public static RandFunction1Node createDouble(Supplier<RandFunction1_Double> function) { + return RandFunction1NodeGen.create(RandFunctionExecutorBaseNodeGen.create(RandFunctionDoubleExecutorNodeGen::create, function)); } static { diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java index ebba5274acc538099ba8d71b3b7b69dfcbbbc888..51564fd6f8bdcf5eb948c22d3c11ea76d7cc89bf 100644 --- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java +++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctionsNodes.java @@ -46,8 +46,9 @@ import com.oracle.truffle.r.runtime.data.RDouble; import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor; -import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess; +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.data.nodes.VectorAccess.RandomIterator; import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function2_1; import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function2_2; import com.oracle.truffle.r.runtime.nmath.MathFunctions.Function3_1; @@ -374,10 +375,11 @@ public final class StatsFunctionsNodes { casts.arg(6).asDoubleVector().findFirst(); } - @Specialization + @Specialization(guards = {"xAccess.supports(x)", "yAccess.supports(y)", "vAccess.supports(v)"}) protected RDoubleVector approx(RAbstractDoubleVector x, RAbstractDoubleVector y, RAbstractDoubleVector v, int method, double yl, double yr, double f, - @Cached("create()") VectorReadAccess.Double xAccess, - @Cached("create()") VectorReadAccess.Double yAccess) { + @Cached("x.access()") VectorAccess xAccess, + @Cached("y.access()") VectorAccess yAccess, + @Cached("v.access()") VectorAccess vAccess) { int nx = x.getLength(); int nout = v.getLength(); double[] yout = new double[nout]; @@ -390,14 +392,21 @@ public final class StatsFunctionsNodes { apprMeth.yhigh = yr; naCheck.enable(true); - ReadAccessor.Double xAccessor = new ReadAccessor.Double(x, xAccess); - ReadAccessor.Double yAccessor = new ReadAccessor.Double(y, yAccess); - for (int i = 0; i < nout; i++) { - double xouti = v.getDataAt(i); - yout[i] = RRuntime.isNAorNaN(xouti) ? xouti : approx1(xouti, xAccessor, yAccessor, nx, apprMeth); - naCheck.check(yout[i]); + try (RandomIterator xIter = xAccess.randomAccess(x); RandomIterator yIter = yAccess.randomAccess(y); SequentialIterator vIter = vAccess.access(v)) { + int i = 0; + while (vAccess.next(vIter)) { + double xouti = vAccess.getDouble(vIter); + yout[i] = RRuntime.isNAorNaN(xouti) ? xouti : approx1(xouti, xAccess, xIter, yAccess, yIter, nx, apprMeth); + naCheck.check(yout[i]); + i++; + } + return RDataFactory.createDoubleVector(yout, naCheck.neverSeenNA()); } - return RDataFactory.createDoubleVector(yout, naCheck.neverSeenNA()); + } + + @Specialization(replaces = "approx") + protected RDoubleVector approxGeneric(RAbstractDoubleVector x, RAbstractDoubleVector y, RAbstractDoubleVector v, int method, double yl, double yr, double f) { + return approx(x, y, v, method, yl, yr, f, x.slowPathAccess(), y.slowPathAccess(), v.slowPathAccess()); } private static class ApprMeth { @@ -408,32 +417,29 @@ public final class StatsFunctionsNodes { int kind; } - private static double approx1(double v, ReadAccessor.Double x, ReadAccessor.Double y, int n, + private static double approx1(double v, VectorAccess xAccess, RandomIterator xIter, VectorAccess yAccess, RandomIterator yIter, int n, ApprMeth apprMeth) { /* Approximate y(v), given (x,y)[i], i = 0,..,n-1 */ - int i; - int j; - int ij; if (n == 0) { return RRuntime.DOUBLE_NA; } - i = 0; - j = n - 1; - + int i = 0; + int j = n - 1; /* handle out-of-domain points */ - if (v < x.getDataAt(i)) { + if (v < xAccess.getDouble(xIter, i)) { return apprMeth.ylow; } - if (v > x.getDataAt(j)) { + if (v > xAccess.getDouble(xIter, j)) { return apprMeth.yhigh; } /* find the correct interval by bisection */ while (i < j - 1) { /* x.getDataAt(i) <= v <= x.getDataAt(j) */ - ij = (i + j) / 2; /* i+1 <= ij <= j-1 */ - if (v < x.getDataAt(ij)) { + int ij = (i + j) / 2; + /* i+1 <= ij <= j-1 */ + if (v < xAccess.getDouble(xIter, ij)) { j = ij; } else { i = ij; @@ -444,18 +450,22 @@ public final class StatsFunctionsNodes { /* interpolation */ - if (v == x.getDataAt(j)) { - return y.getDataAt(j); + double xJ = xAccess.getDouble(xIter, j); + double yJ = yAccess.getDouble(yIter, j); + if (v == xJ) { + return yJ; } - if (v == x.getDataAt(i)) { - return y.getDataAt(i); + double xI = xAccess.getDouble(xIter, i); + double yI = yAccess.getDouble(yIter, i); + if (v == xI) { + return yI; } /* impossible: if(x.getDataAt(j) == x.getDataAt(i)) return y.getDataAt(i); */ if (apprMeth.kind == 1) { /* linear */ - return y.getDataAt(i) + (y.getDataAt(j) - y.getDataAt(i)) * ((v - x.getDataAt(i)) / (x.getDataAt(j) - x.getDataAt(i))); + return yI + (yJ - yI) * ((v - xI) / (xJ - xI)); } else { /* 2 : constant */ - return (apprMeth.f1 != 0.0 ? y.getDataAt(i) * apprMeth.f1 : 0.0) + (apprMeth.f2 != 0.0 ? y.getDataAt(j) * apprMeth.f2 : 0.0); + return (apprMeth.f1 != 0.0 ? yI * apprMeth.f1 : 0.0) + (apprMeth.f2 != 0.0 ? yJ * apprMeth.f2 : 0.0); } }/* approx1() */ diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java index 515d57eec9c176430c07e87124e1c292f75e5d93..8ee5500175998956147d01d844bca7b1ed517ce0 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/AnyNA.java @@ -27,6 +27,7 @@ import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE_SUMMARY; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; +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.api.profiles.ValueProfile; @@ -39,19 +40,23 @@ import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; -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.ops.na.NACheck; +import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; @RBuiltin(name = "anyNA", kind = PRIMITIVE, parameterNames = {"x", "recursive"}, dispatch = INTERNAL_GENERIC, behavior = PURE_SUMMARY) public abstract class AnyNA extends RBuiltinNode.Arg2 { - private final NACheck naCheck = NACheck.create(); + // true if this is the first recursive level + protected final boolean isRecursive; + + protected AnyNA() { + this.isRecursive = false; + } + + protected AnyNA(boolean isRecursive) { + this.isRecursive = isRecursive; + } public abstract byte execute(Object value, boolean recursive); @@ -65,117 +70,132 @@ public abstract class AnyNA extends RBuiltinNode.Arg2 { return new Object[]{RMissing.instance, RRuntime.LOGICAL_FALSE}; } - private static byte doScalar(boolean isNA) { - return RRuntime.asLogical(isNA); - } - - @FunctionalInterface - private interface VectorIndexPredicate<T extends RAbstractVector> { - boolean apply(T vector, int index); - } - - private <T extends RAbstractVector> byte doVector(T vector, VectorIndexPredicate<T> predicate) { - naCheck.enable(vector); - for (int i = 0; i < vector.getLength(); i++) { - if (predicate.apply(vector, i)) { - return RRuntime.LOGICAL_TRUE; - } - } - return RRuntime.LOGICAL_FALSE; - } - @Specialization protected byte isNA(byte value, @SuppressWarnings("unused") boolean recursive) { - return doScalar(RRuntime.isNA(value)); + return RRuntime.asLogical(RRuntime.isNA(value)); } @Specialization protected byte isNA(int value, @SuppressWarnings("unused") boolean recursive) { - return doScalar(RRuntime.isNA(value)); + return RRuntime.asLogical(RRuntime.isNA(value)); } @Specialization protected byte isNA(double value, @SuppressWarnings("unused") boolean recursive) { - return doScalar(RRuntime.isNAorNaN(value)); + return RRuntime.asLogical(RRuntime.isNAorNaN(value)); } @Specialization protected byte isNA(RComplex value, @SuppressWarnings("unused") boolean recursive) { - return doScalar(RRuntime.isNA(value)); + return RRuntime.asLogical(RRuntime.isNA(value)); } @Specialization protected byte isNA(String value, @SuppressWarnings("unused") boolean recursive) { - return doScalar(RRuntime.isNA(value)); + return RRuntime.asLogical(RRuntime.isNA(value)); } @Specialization @SuppressWarnings("unused") protected byte isNA(RRaw value, boolean recursive) { - return doScalar(false); + return RRuntime.LOGICAL_FALSE; } @Specialization protected byte isNA(@SuppressWarnings("unused") RNull value, @SuppressWarnings("unused") boolean recursive) { - return doScalar(false); - } - - @Specialization - protected byte isNA(RAbstractIntVector vector, @SuppressWarnings("unused") boolean recursive) { - return doVector(vector, (v, i) -> naCheck.check(v.getDataAt(i))); - } - - @Specialization - protected byte isNA(RAbstractDoubleVector vector, @SuppressWarnings("unused") boolean recursive) { - // since - return doVector(vector, (v, i) -> naCheck.checkNAorNaN(v.getDataAt(i))); + return RRuntime.LOGICAL_FALSE; } - @Specialization - protected byte isNA(RAbstractComplexVector vector, @SuppressWarnings("unused") boolean recursive) { - return doVector(vector, (v, i) -> naCheck.check(v.getDataAt(i))); + @Specialization(guards = "xAccess.supports(x)") + protected byte anyNACached(RAbstractAtomicVector x, @SuppressWarnings("unused") boolean recursive, + @Cached("x.access()") VectorAccess xAccess) { + switch (xAccess.getType()) { + case Logical: + case Integer: + case Character: + // shortcut when we know there's no NAs + if (!x.isComplete()) { + try (SequentialIterator iter = xAccess.access(x)) { + while (xAccess.next(iter)) { + if (xAccess.isNA(iter)) { + return RRuntime.LOGICAL_TRUE; + } + } + } + } + break; + case Raw: + return RRuntime.LOGICAL_FALSE; + case Double: + // we need to check for NaNs + try (SequentialIterator iter = xAccess.access(x)) { + while (xAccess.next(iter)) { + if (xAccess.na.checkNAorNaN(xAccess.getDouble(iter))) { + return RRuntime.LOGICAL_TRUE; + } + } + } + break; + case Complex: + // we need to check for NaNs + try (SequentialIterator iter = xAccess.access(x)) { + while (xAccess.next(iter)) { + if (xAccess.na.checkNAorNaN(xAccess.getComplexR(iter)) || xAccess.na.checkNAorNaN(xAccess.getComplexR(iter))) { + return RRuntime.LOGICAL_TRUE; + } + } + } + break; + } + return RRuntime.LOGICAL_FALSE; } - @Specialization - protected byte isNA(RAbstractStringVector vector, @SuppressWarnings("unused") boolean recursive) { - return doVector(vector, (v, i) -> naCheck.check(v.getDataAt(i))); + @Specialization(replaces = "anyNACached") + protected byte anyNAGeneric(RAbstractAtomicVector x, boolean recursive) { + return anyNACached(x, recursive, x.slowPathAccess()); } - @Specialization - protected byte isNA(RAbstractLogicalVector vector, @SuppressWarnings("unused") boolean recursive) { - return doVector(vector, (v, i) -> naCheck.check(v.getDataAt(i))); + protected AnyNA createRecursive() { + return AnyNANodeGen.create(true); } - @Specialization - protected byte isNA(@SuppressWarnings("unused") RAbstractRawVector vector, @SuppressWarnings("unused") boolean recursive) { - return doScalar(false); + @Specialization(guards = {"isRecursive", "recursive == cachedRecursive"}) + protected byte isNARecursive(RList list, boolean recursive, + @Cached("recursive") boolean cachedRecursive, + @Cached("createClassProfile()") ValueProfile elementProfile, + @Cached("create()") RLengthNode length) { + if (cachedRecursive) { + for (int i = 0; i < list.getLength(); i++) { + Object value = elementProfile.profile(list.getDataAt(i)); + if (length.executeInteger(value) > 0) { + if (recursive(recursive, value) == RRuntime.LOGICAL_TRUE) { + return RRuntime.LOGICAL_TRUE; + } + } + } + } + return RRuntime.LOGICAL_FALSE; } - protected AnyNA createRecursive() { - return AnyNANodeGen.create(); + @TruffleBoundary + private byte recursive(boolean recursive, Object value) { + return execute(value, recursive); } - @Specialization(guards = "recursive") + @Specialization(guards = {"!isRecursive", "recursive == cachedRecursive"}) protected byte isNA(RList list, boolean recursive, + @Cached("recursive") boolean cachedRecursive, @Cached("createRecursive()") AnyNA recursiveNode, @Cached("createClassProfile()") ValueProfile elementProfile, @Cached("create()") RLengthNode length) { - for (int i = 0; i < list.getLength(); i++) { Object value = elementProfile.profile(list.getDataAt(i)); - if (length.executeInteger(value) > 0) { - byte result = recursiveNode.execute(value, recursive); - if (result == RRuntime.LOGICAL_TRUE) { + if (cachedRecursive || length.executeInteger(value) == 1) { + if (recursiveNode.execute(value, recursive) == RRuntime.LOGICAL_TRUE) { return RRuntime.LOGICAL_TRUE; } } } return RRuntime.LOGICAL_FALSE; } - - @Specialization(guards = "!recursive") - @SuppressWarnings("unused") - protected byte isNA(RList list, boolean recursive) { - return RRuntime.LOGICAL_FALSE; - } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java index 533a4b2caa36879ed71a8fe176522ab6b9c50ee8..f23c6fd39aecbd44a4aa4cfbec5c28731bc57317 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Array.java @@ -30,46 +30,27 @@ 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; +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.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; -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; -import com.oracle.truffle.r.runtime.data.RIntVector; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -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; -/** - * The {@code} .Internal part of the {@code array} function. The R code may alter the arguments - * before calling {@code .Internal}. - * - * <pre> - * array <- function(data = NA, dim = length(data), dimnames = NULL) { .Internal.array(data, dim, dimnames) } - * </pre> - * - * TODO complete. This is sufficient for the b25 benchmark use. - */ @RBuiltin(name = "array", kind = INTERNAL, parameterNames = {"data", "dim", "dimnames"}, behavior = PURE) public abstract class Array extends RBuiltinNode.Arg3 { @Child private UpdateDimNames updateDimNames; - private final ConditionProfile nonEmptyVectorProfile = ConditionProfile.createBinaryProfile(); // it's OK for the following method to update dimnames in-place as the container is "fresh" private void updateDimNames(RAbstractContainer container, Object o) { @@ -87,227 +68,76 @@ public abstract class Array extends RBuiltinNode.Arg3 { casts.arg("dimnames").defaultError(RError.Message.DIMNAMES_LIST).allowNull().mustBe(instanceOf(RList.class)); } - private int dimDataHelper(RAbstractIntVector dim, int[] dimData) { + @Specialization(guards = {"dataAccess.supports(data)", "dimAccess.supports(dim)"}) + protected RAbstractVector arrayCached(RAbstractVector data, RAbstractIntVector dim, Object dimNames, + @Cached("data.access()") VectorAccess dataAccess, + @Cached("dim.access()") VectorAccess dimAccess, + @Cached("createNew(dataAccess.getType())") VectorAccess resultAccess, + @Cached("createBinaryProfile()") ConditionProfile hasDimNames, + @Cached("createBinaryProfile()") ConditionProfile isEmpty, + @Cached("create()") VectorFactory factory) { + // extract dimensions and compute total length + int[] dimArray; int totalLength = 1; - int seenNegative = 0; - for (int i = 0; i < dim.getLength(); i++) { - dimData[i] = dim.getDataAt(i); - if (dimData[i] < 0) { - seenNegative++; + boolean negativeDims = false; + try (SequentialIterator dimIter = dimAccess.access(dim)) { + dimArray = new int[dimAccess.getLength(dimIter)]; + while (dimAccess.next(dimIter)) { + int dimValue = dimAccess.getInt(dimIter); + if (dimValue < 0) { + negativeDims = true; + } + totalLength *= dimValue; + dimArray[dimIter.getIndex()] = dimValue; } - totalLength *= dimData[i]; } - if (seenNegative == dim.getLength() && seenNegative != 0) { - throw error(RError.Message.DIMS_CONTAIN_NEGATIVE_VALUES); - } else if (seenNegative > 0) { + if (totalLength < 0) { throw error(RError.Message.NEGATIVE_LENGTH_VECTORS_NOT_ALLOWED); + } else if (negativeDims) { + throw error(RError.Message.DIMS_CONTAIN_NEGATIVE_VALUES); } - return totalLength; - } - - private RIntVector doArrayInt(RAbstractIntVector vec, RAbstractIntVector dim) { - int[] dimData = new int[dim.getLength()]; - int totalLength = dimDataHelper(dim, dimData); - int[] data = new int[totalLength]; - int vecLength = vec.getLength(); - if (nonEmptyVectorProfile.profile(totalLength > 0 && vecLength > 0)) { - for (int i = 0; i < totalLength; i++) { - data[i] = vec.getDataAt(i % vec.getLength()); - } - return RDataFactory.createIntVector(data, vec.isComplete(), dimData); - } else { - for (int i = 0; i < totalLength; i++) { - data[i] = RRuntime.INT_NA; - } - return RDataFactory.createIntVector(data, RDataFactory.INCOMPLETE_VECTOR, dimData); - } - } - - @Specialization - protected RIntVector doArrayNoDimNames(RAbstractIntVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) { - return doArrayInt(vec, dim); - } - - @Specialization - protected RIntVector doArray(RAbstractIntVector vec, RAbstractIntVector dim, RList dimnames) { - RIntVector ret = doArrayInt(vec, dim); - updateDimNames(ret, dimnames); - return ret; - } - - private RDoubleVector doArrayDouble(RAbstractDoubleVector vec, RAbstractIntVector dim) { - int[] dimData = new int[dim.getLength()]; - int totalLength = dimDataHelper(dim, dimData); - double[] data = new double[totalLength]; - int vecLength = vec.getLength(); - if (totalLength > 0 && vecLength > 0) { - for (int i = 0; i < totalLength; i++) { - data[i] = vec.getDataAt(i % vec.getLength()); - } - return RDataFactory.createDoubleVector(data, vec.isComplete(), dimData); - } else { - for (int i = 0; i < totalLength; i++) { - data[i] = RRuntime.DOUBLE_NA; - } - return RDataFactory.createDoubleVector(data, RDataFactory.INCOMPLETE_VECTOR, dimData); - } - } - - @Specialization - protected RDoubleVector doArrayNoDimNames(RAbstractDoubleVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) { - return doArrayDouble(vec, dim); - } - - @Specialization - protected RDoubleVector doArray(RAbstractDoubleVector vec, RAbstractIntVector dim, RList dimnames) { - RDoubleVector ret = doArrayDouble(vec, dim); - updateDimNames(ret, dimnames); - return ret; - } - - private RLogicalVector doArrayLogical(RAbstractLogicalVector vec, RAbstractIntVector dim) { - int[] dimData = new int[dim.getLength()]; - int totalLength = dimDataHelper(dim, dimData); - byte[] data = new byte[totalLength]; - int vecLength = vec.getLength(); - if (totalLength > 0 && vecLength > 0) { - for (int i = 0; i < totalLength; i++) { - data[i] = vec.getDataAt(i % vec.getLength()); - } - return RDataFactory.createLogicalVector(data, vec.isComplete(), dimData); - } else { - for (int i = 0; i < totalLength; i++) { - data[i] = RRuntime.LOGICAL_NA; - } - return RDataFactory.createLogicalVector(data, RDataFactory.INCOMPLETE_VECTOR, dimData); - } - } - - @Specialization - protected RLogicalVector doArrayNoDimNames(RAbstractLogicalVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) { - return doArrayLogical(vec, dim); - } - - @Specialization - protected RLogicalVector doArray(RAbstractLogicalVector vec, RAbstractIntVector dim, RList dimnames) { - RLogicalVector ret = doArrayLogical(vec, dim); - updateDimNames(ret, dimnames); - return ret; - } - - private RStringVector doArrayString(RAbstractStringVector vec, RAbstractIntVector dim) { - int[] dimData = new int[dim.getLength()]; - int totalLength = dimDataHelper(dim, dimData); - String[] data = new String[totalLength]; - int vecLength = vec.getLength(); - if (totalLength > 0 && vecLength > 0) { - for (int i = 0; i < totalLength; i++) { - data[i] = vec.getDataAt(i % vec.getLength()); - } - return RDataFactory.createStringVector(data, vec.isComplete(), dimData); - } else { - String empty = Utils.intern(""); - for (int i = 0; i < totalLength; i++) { - data[i] = empty; - } - return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR, dimData); - } - } - - @Specialization - protected RStringVector doArrayNoDimNames(RAbstractStringVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) { - return doArrayString(vec, dim); - } - @Specialization - protected RStringVector doArray(RAbstractStringVector vec, RAbstractIntVector dim, RList dimnames) { - RStringVector ret = doArrayString(vec, dim); - updateDimNames(ret, dimnames); - return ret; - } - - private RComplexVector doArrayComplex(RAbstractComplexVector vec, RAbstractIntVector dim) { - int[] dimData = new int[dim.getLength()]; - int totalLength = dimDataHelper(dim, dimData); - double[] data = new double[totalLength << 1]; - int ind = 0; - int vecLength = vec.getLength(); - if (totalLength > 0 && vecLength > 0) { - for (int i = 0; i < totalLength; i++) { - RComplex d = vec.getDataAt(i % vec.getLength()); - data[ind++] = d.getRealPart(); - data[ind++] = d.getImaginaryPart(); - } - return RDataFactory.createComplexVector(data, vec.isComplete(), dimData); - } else { - for (int i = 0; i < totalLength; i++) { - data[ind++] = RRuntime.COMPLEX_NA_REAL_PART; - data[ind++] = RRuntime.COMPLEX_NA_IMAGINARY_PART; + RAbstractVector result = factory.createUninitializedVector(dataAccess.getType(), totalLength, dimArray, null, null); + + try (SequentialIterator resultIter = resultAccess.access(result); SequentialIterator dataIter = dataAccess.access(data)) { + if (isEmpty.profile(dataAccess.getLength(dataIter) == 0)) { + if (dataAccess.getType() == RType.Character) { + // character vectors are initialized with "" instead of NA + while (resultAccess.next(resultIter)) { + resultAccess.setString(resultIter, ""); + } + result.setComplete(true); + } else { + while (resultAccess.next(resultIter)) { + resultAccess.setNA(resultIter); + } + result.setComplete(false); + } + } else { + while (resultAccess.next(resultIter)) { + dataAccess.nextWithWrap(dataIter); + resultAccess.setFromSameType(resultIter, dataAccess, dataIter); + } + result.setComplete(!dataAccess.na.isEnabled()); } - return RDataFactory.createComplexVector(data, RDataFactory.INCOMPLETE_VECTOR, dimData); } - } - - @Specialization - protected RComplexVector doArrayNoDimNames(RAbstractComplexVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) { - return doArrayComplex(vec, dim); - } - - @Specialization - protected RComplexVector doArray(RAbstractComplexVector vec, RAbstractIntVector dim, RList dimnames) { - RComplexVector ret = doArrayComplex(vec, dim); - updateDimNames(ret, dimnames); - return ret; - } - private RRawVector doArrayRaw(RAbstractRawVector vec, RAbstractIntVector dim) { - int[] dimData = new int[dim.getLength()]; - int totalLength = dimDataHelper(dim, dimData); - byte[] data = new byte[totalLength]; - int vecLength = vec.getLength(); - if (totalLength > 0 && vecLength > 0) { - for (int i = 0; i < totalLength; i++) { - data[i] = vec.getRawDataAt(i % vec.getLength()); - } + // dimensions are set as a separate step so they are checked for validity + if (hasDimNames.profile(dimNames instanceof RList)) { + updateDimNames(result, dimNames); } else { - for (int i = 0; i < totalLength; i++) { - data[i] = 0; - } - } - return RDataFactory.createRawVector(data, dimData); - } - - @Specialization - protected RRawVector doArrayNoDimNames(RAbstractRawVector vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) { - return doArrayRaw(vec, dim); - } - - @Specialization - protected RRawVector doArray(RAbstractRawVector vec, RAbstractIntVector dim, RList dimnames) { - RRawVector ret = doArrayRaw(vec, dim); - updateDimNames(ret, dimnames); - return ret; - } - - private RList doArrayList(RList vec, RAbstractIntVector dim) { - int[] dimData = new int[dim.getLength()]; - int totalLength = dimDataHelper(dim, dimData); - Object[] data = new Object[totalLength]; - for (int i = 0; i < totalLength; i++) { - data[i] = vec.getDataAt(i % vec.getLength()); + assert dimNames instanceof RNull; } - return RDataFactory.createList(data, dimData); - } - - @Specialization - protected RList doArrayNoDimeNames(RList vec, RAbstractIntVector dim, @SuppressWarnings("unused") RNull dimnames) { - return doArrayList(vec, dim); + return result; } - @Specialization - protected RList doArray(RList vec, RAbstractIntVector dim, RList dimnames) { - RList ret = doArrayList(vec, dim); - updateDimNames(ret, dimnames); - return ret; + @Specialization(replaces = "arrayCached") + @TruffleBoundary + protected RAbstractVector arrayGeneric(RAbstractVector data, RAbstractIntVector dim, Object dimNames, + @Cached("createBinaryProfile()") ConditionProfile hasDimNames, + @Cached("createBinaryProfile()") ConditionProfile isEmpty, + @Cached("create()") VectorFactory factory) { + VectorAccess dataAccess = data.slowPathAccess(); + return arrayCached(data, dim, dimNames, dataAccess, dim.slowPathAccess(), VectorAccess.createSlowPathNew(dataAccess.getType()), hasDimNames, isEmpty, factory); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java index a4b42e74a116a60e55c8384be8784d202d142c7b..cee07fbd4bbce686c77f167e96131042d7bf0c49 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Cat.java @@ -141,11 +141,11 @@ public abstract class Cat extends RBuiltinNode.Arg6 { } else { validateType(i + 1, obj); for (int j = 0; j < objVec.getLength(); j++) { - stringVecs.add(toString.executeString(objVec.getDataAtAsObject(j), false, "")); + stringVecs.add(toString.executeString(objVec.getDataAtAsObject(j), "")); } } } else { - stringVecs.add(toString.executeString(obj, false, "")); + stringVecs.add(toString.executeString(obj, "")); } } 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/CrossprodCommon.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CrossprodCommon.java index e88dada037ba1aa458c38711edc7073277dca85c..38067a8c5101e45ac6c4ccac6e3bc2d266395b41 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CrossprodCommon.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CrossprodCommon.java @@ -80,7 +80,7 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 { return CrossprodCommonNodeGen.create(false); } - @Specialization(guards = {"x.isMatrix()", "y.isMatrix()"}) + @Specialization(guards = {"getXDimsNode.isMatrix(x)", "getYDimsNode.isMatrix(y)"}) protected RDoubleVector crossprod(RAbstractDoubleVector x, RAbstractDoubleVector y, @Cached("create()") GetDimAttributeNode getXDimsNode, @Cached("create()") GetDimAttributeNode getYDimsNode) { @@ -100,7 +100,7 @@ public abstract class CrossprodCommon extends RBuiltinNode.Arg2 { return copyDimNames(x, y, (RAbstractVector) matMult.executeObject(transposeX(x), transposeY(y))); } - @Specialization(guards = "x.isMatrix()") + @Specialization(guards = "getDimsNode.isMatrix(x)") protected RDoubleVector crossprodDoubleMatrix(RAbstractDoubleVector x, @SuppressWarnings("unused") RNull y, @Cached("create()") GetReadonlyData.Double getReadonlyData, @Cached("create()") GetDimAttributeNode getDimsNode, diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java index 69767d4e3dd9bf4cd91cdf9c527a677e1d101a19..c89d7c817a7af2462be489289b92eece6e822f67 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumProd.java @@ -19,6 +19,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; import java.util.Arrays; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; @@ -32,16 +33,14 @@ import com.oracle.truffle.r.runtime.data.RDoubleVector; import com.oracle.truffle.r.runtime.data.RNull; 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.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.ops.BinaryArithmetic; -import com.oracle.truffle.r.runtime.ops.na.NACheck; @RBuiltin(name = "cumprod", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE) public abstract class CumProd extends RBuiltinNode.Arg1 { - private final NACheck na = NACheck.create(); @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); - @Child private BinaryArithmetic mul = BinaryArithmetic.MULTIPLY.createOperation(); static { @@ -55,63 +54,63 @@ public abstract class CumProd extends RBuiltinNode.Arg1 { } @Specialization - protected RDoubleVector cumNull(@SuppressWarnings("unused") RNull rnull) { + protected RDoubleVector cumNull(@SuppressWarnings("unused") RNull x) { return RDataFactory.createEmptyDoubleVector(); } - @Specialization(guards = "emptyVec.getLength()==0") - protected RAbstractVector cumEmpty(RAbstractComplexVector emptyVec) { - return RDataFactory.createComplexVector(new double[0], true, emptyVec.getNames()); + @Specialization(guards = "xAccess.supports(x)") + protected RDoubleVector cumprodDouble(RAbstractDoubleVector x, + @Cached("x.access()") VectorAccess xAccess) { + try (SequentialIterator iter = xAccess.access(x)) { + double[] array = new double[xAccess.getLength(iter)]; + double prev = 1; + while (xAccess.next(iter)) { + double value = xAccess.getDouble(iter); + if (xAccess.na.check(value)) { + Arrays.fill(array, iter.getIndex(), array.length, RRuntime.DOUBLE_NA); + break; + } + if (xAccess.na.checkNAorNaN(value)) { + Arrays.fill(array, iter.getIndex(), array.length, Double.NaN); + break; + } + prev = mul.op(prev, value); + assert !RRuntime.isNA(prev) : "double multiplication should not introduce NAs"; + array[iter.getIndex()] = prev; + } + return RDataFactory.createDoubleVector(array, xAccess.na.neverSeenNA(), getNamesNode.getNames(x)); + } } - @Specialization(guards = "emptyVec.getLength()==0") - protected RAbstractVector cumEmpty(RAbstractDoubleVector emptyVec) { - return RDataFactory.createDoubleVector(new double[0], true, emptyVec.getNames()); + @Specialization(replaces = "cumprodDouble") + protected RDoubleVector cumprodDoubleGeneric(RAbstractDoubleVector x) { + return cumprodDouble(x, x.slowPathAccess()); } - @Specialization - protected RDoubleVector cumprod(RAbstractDoubleVector arg) { - double[] array = new double[arg.getLength()]; - na.enable(arg); - double prev = 1; - int i; - for (i = 0; i < arg.getLength(); i++) { - double value = arg.getDataAt(i); - if (na.check(value)) { - Arrays.fill(array, i, array.length, RRuntime.DOUBLE_NA); - break; - } - if (na.checkNAorNaN(value)) { - Arrays.fill(array, i, array.length, Double.NaN); - break; + @Specialization(guards = "xAccess.supports(x)") + protected RComplexVector cumprodComplex(RAbstractComplexVector x, + @Cached("x.access()") VectorAccess xAccess) { + try (SequentialIterator iter = xAccess.access(x)) { + double[] array = new double[xAccess.getLength(iter) * 2]; + RComplex prev = RDataFactory.createComplex(1, 0); + while (xAccess.next(iter)) { + double real = xAccess.getComplexR(iter); + double imag = xAccess.getComplexI(iter); + if (xAccess.na.check(real, imag)) { + Arrays.fill(array, 2 * iter.getIndex(), array.length, RRuntime.DOUBLE_NA); + break; + } + prev = mul.op(prev.getRealPart(), prev.getImaginaryPart(), real, imag); + assert !RRuntime.isNA(prev) : "complex multiplication should not introduce NAs"; + array[iter.getIndex() * 2] = prev.getRealPart(); + array[iter.getIndex() * 2 + 1] = prev.getImaginaryPart(); } - prev = mul.op(prev, value); - array[i] = prev; + return RDataFactory.createComplexVector(array, xAccess.na.neverSeenNA(), getNamesNode.getNames(x)); } - return RDataFactory.createDoubleVector(array, na.neverSeenNA(), getNamesNode.getNames(arg)); } - @Specialization - protected RComplexVector cumprod(RAbstractComplexVector arg) { - double[] array = new double[arg.getLength() * 2]; - na.enable(arg); - RComplex prev = RDataFactory.createComplex(1, 0); - int i; - for (i = 0; i < arg.getLength(); i++) { - RComplex value = arg.getDataAt(i); - if (na.check(value)) { - break; - } - prev = mul.op(prev.getRealPart(), prev.getImaginaryPart(), value.getRealPart(), value.getImaginaryPart()); - if (na.check(prev)) { - break; - } - array[i * 2] = prev.getRealPart(); - array[i * 2 + 1] = prev.getImaginaryPart(); - } - if (!na.neverSeenNA()) { - Arrays.fill(array, 2 * i, array.length, RRuntime.DOUBLE_NA); - } - return RDataFactory.createComplexVector(array, na.neverSeenNA(), getNamesNode.getNames(arg)); + @Specialization(replaces = "cumprodComplex") + protected RComplexVector cumprodComplexGeneric(RAbstractComplexVector x) { + return cumprodComplex(x, x.slowPathAccess()); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java index f0b47f2e76becdd87dc3801075fdd341d1a594bb..a84d226b6aa3e719e9a0865df57368ac10a44e67 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/CumSum.java @@ -36,6 +36,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; import java.util.Arrays; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; @@ -46,22 +47,20 @@ 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; -import com.oracle.truffle.r.runtime.data.RIntSequence; import com.oracle.truffle.r.runtime.data.RIntVector; import com.oracle.truffle.r.runtime.data.RNull; 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.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.ops.BinaryArithmetic; -import com.oracle.truffle.r.runtime.ops.na.NACheck; @RBuiltin(name = "cumsum", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = MATH_GROUP_GENERIC, behavior = PURE) public abstract class CumSum extends RBuiltinNode.Arg1 { - private final NACheck na = NACheck.create(); @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); - @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation(); static { @@ -81,100 +80,107 @@ public abstract class CumSum extends RBuiltinNode.Arg1 { } @Specialization - protected RDoubleVector cumNull(@SuppressWarnings("unused") RNull rnull) { + protected RDoubleVector cumNull(@SuppressWarnings("unused") RNull x) { return RDataFactory.createEmptyDoubleVector(); } - @Specialization(guards = "emptyVec.getLength()==0") - protected RAbstractVector cumEmpty(RAbstractComplexVector emptyVec) { - return RDataFactory.createComplexVector(new double[0], true, emptyVec.getNames()); + @Specialization(guards = "x.getLength()==0") + protected RAbstractVector cumEmpty(RAbstractComplexVector x) { + return RDataFactory.createComplexVector(new double[0], true, getNamesNode.getNames(x)); } - @Specialization(guards = "emptyVec.getLength()==0") - protected RAbstractVector cumEmpty(RAbstractDoubleVector emptyVec) { - return RDataFactory.createDoubleVector(new double[0], true, emptyVec.getNames()); + @Specialization(guards = "x.getLength()==0") + protected RAbstractVector cumEmpty(RAbstractDoubleVector x) { + return RDataFactory.createDoubleVector(new double[0], true, getNamesNode.getNames(x)); } - @Specialization(guards = "emptyVec.getLength()==0") - protected RAbstractVector cumEmpty(RAbstractIntVector emptyVec) { - return RDataFactory.createIntVector(new int[0], true, emptyVec.getNames()); + @Specialization(guards = "x.getLength()==0") + protected RAbstractVector cumEmpty(RAbstractIntVector x) { + return RDataFactory.createIntVector(new int[0], true, getNamesNode.getNames(x)); } - @Specialization - protected RIntVector cumsum(RIntSequence arg) { - int[] res = new int[arg.getLength()]; - int current = arg.getStart(); - int prev = 0; - na.enable(true); - for (int i = 0; i < arg.getLength(); i++) { - prev = add.op(prev, current); - if (na.check(prev)) { - Arrays.fill(res, i, res.length, RRuntime.INT_NA); - break; + @Specialization(guards = "xAccess.supports(x)") + protected RIntVector cumsumInt(RAbstractIntVector x, + @Cached("x.access()") VectorAccess xAccess) { + try (SequentialIterator iter = xAccess.access(x)) { + int[] array = new int[xAccess.getLength(iter)]; + int prev = 0; + while (xAccess.next(iter)) { + int value = xAccess.getInt(iter); + if (xAccess.na.check(value)) { + Arrays.fill(array, iter.getIndex(), array.length, RRuntime.INT_NA); + break; + } + prev = add.op(prev, value); + // integer addition can introduce NAs + if (add.introducesNA() && RRuntime.isNA(prev)) { + Arrays.fill(array, iter.getIndex(), array.length, RRuntime.INT_NA); + break; + } + array[iter.getIndex()] = prev; } - current += arg.getStride(); - res[i] = prev; + return RDataFactory.createIntVector(array, xAccess.na.neverSeenNA() && !add.introducesNA(), getNamesNode.getNames(x)); } - return RDataFactory.createIntVector(res, na.neverSeenNA(), getNamesNode.getNames(arg)); } - @Specialization - protected RDoubleVector cumsum(RAbstractDoubleVector arg) { - double[] res = new double[arg.getLength()]; - double prev = 0.0; - na.enable(true); - for (int i = 0; i < arg.getLength(); i++) { - double value = arg.getDataAt(i); - // cumsum behaves different than cumprod for NaNs: - if (na.check(value)) { - Arrays.fill(res, i, res.length, RRuntime.DOUBLE_NA); - break; - } else if (na.checkNAorNaN(value)) { - Arrays.fill(res, i, res.length, Double.NaN); - break; - } - prev = add.op(prev, value); - res[i] = prev; - } - return RDataFactory.createDoubleVector(res, na.neverSeenNA(), getNamesNode.getNames(arg)); + @Specialization(replaces = "cumsumInt") + protected RIntVector cumsumIntGeneric(RAbstractIntVector x) { + return cumsumInt(x, x.slowPathAccess()); } - @Specialization - protected RIntVector cumsum(RAbstractIntVector arg) { - int[] res = new int[arg.getLength()]; - int prev = 0; - int i; - na.enable(true); - for (i = 0; i < arg.getLength(); i++) { - if (na.check(arg.getDataAt(i))) { - break; - } - prev = add.op(prev, arg.getDataAt(i)); - if (na.check(prev)) { - break; + @Specialization(guards = "xAccess.supports(x)") + protected RDoubleVector cumsumDouble(RAbstractDoubleVector x, + @Cached("x.access()") VectorAccess xAccess) { + try (SequentialIterator iter = xAccess.access(x)) { + double[] array = new double[xAccess.getLength(iter)]; + double prev = 0; + while (xAccess.next(iter)) { + double value = xAccess.getDouble(iter); + if (xAccess.na.check(value)) { + Arrays.fill(array, iter.getIndex(), array.length, RRuntime.DOUBLE_NA); + break; + } + if (xAccess.na.checkNAorNaN(value)) { + Arrays.fill(array, iter.getIndex(), array.length, Double.NaN); + break; + } + prev = add.op(prev, value); + assert !RRuntime.isNA(prev) : "double addition should not introduce NAs"; + array[iter.getIndex()] = prev; } - res[i] = prev; + return RDataFactory.createDoubleVector(array, xAccess.na.neverSeenNA(), getNamesNode.getNames(x)); } - if (!na.neverSeenNA()) { - Arrays.fill(res, i, res.length, RRuntime.INT_NA); - } - return RDataFactory.createIntVector(res, na.neverSeenNA(), getNamesNode.getNames(arg)); } - @Specialization - protected RComplexVector cumsum(RAbstractComplexVector arg) { - double[] res = new double[arg.getLength() * 2]; - RComplex prev = RDataFactory.createComplex(0.0, 0.0); - na.enable(true); - for (int i = 0; i < arg.getLength(); i++) { - prev = add.op(prev.getRealPart(), prev.getImaginaryPart(), arg.getDataAt(i).getRealPart(), arg.getDataAt(i).getImaginaryPart()); - if (na.check(arg.getDataAt(i))) { - Arrays.fill(res, 2 * i, res.length, RRuntime.DOUBLE_NA); - break; + @Specialization(replaces = "cumsumDouble") + protected RDoubleVector cumsumDoubleGeneric(RAbstractDoubleVector x) { + return cumsumDouble(x, x.slowPathAccess()); + } + + @Specialization(guards = "xAccess.supports(x)") + protected RComplexVector cumsumComplex(RAbstractComplexVector x, + @Cached("x.access()") VectorAccess xAccess) { + try (SequentialIterator iter = xAccess.access(x)) { + double[] array = new double[xAccess.getLength(iter) * 2]; + RComplex prev = RDataFactory.createComplex(0, 0); + while (xAccess.next(iter)) { + double real = xAccess.getComplexR(iter); + double imag = xAccess.getComplexI(iter); + if (xAccess.na.check(real, imag)) { + Arrays.fill(array, 2 * iter.getIndex(), array.length, RRuntime.DOUBLE_NA); + break; + } + prev = add.op(prev.getRealPart(), prev.getImaginaryPart(), real, imag); + assert !RRuntime.isNA(prev) : "complex addition should not introduce NAs"; + array[iter.getIndex() * 2] = prev.getRealPart(); + array[iter.getIndex() * 2 + 1] = prev.getImaginaryPart(); } - res[2 * i] = prev.getRealPart(); - res[2 * i + 1] = prev.getImaginaryPart(); + return RDataFactory.createComplexVector(array, xAccess.na.neverSeenNA(), getNamesNode.getNames(x)); } - return RDataFactory.createComplexVector(res, na.neverSeenNA(), getNamesNode.getNames(arg)); + } + + @Specialization(replaces = "cumsumComplex") + protected RComplexVector cumsumComplexGeneric(RAbstractComplexVector x) { + return cumsumComplex(x, x.slowPathAccess()); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java index ca1cda7f78336c92bba9dfc5fa216436a663e481..a3e832046227da221745e0023bed1b3cac7d97fe 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Diag.java @@ -14,26 +14,26 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.asDoubleVector; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.complexValue; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte0; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.logicalValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notIntNA; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.nullValue; 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; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; -import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.RNull; -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.RAbstractLogicalVector; 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.RandomIterator; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; @RBuiltin(name = "diag", kind = INTERNAL, parameterNames = {"x", "nrow", "ncol"}, behavior = PURE) public abstract class Diag extends RBuiltinNode.Arg3 { @@ -48,7 +48,6 @@ public abstract class Diag extends RBuiltinNode.Arg3 { private int checkX(RAbstractVector x, int nrow, int ncol) { int mn = (nrow < ncol) ? nrow : ncol; if (mn > 0 && x.getLength() == 0) { - CompilerDirectives.transferToInterpreter(); throw error(Message.POSITIVE_LENGTH, "x"); } return mn; @@ -56,8 +55,8 @@ public abstract class Diag extends RBuiltinNode.Arg3 { @Specialization protected Object diag(@SuppressWarnings("unused") RNull x, int nrow, int ncol) { - if (nrow == 0 && ncol == 0) { - return RDataFactory.createDoubleVector(new double[]{}, true, new int[]{0, 0}); + if (nrow == 0 || ncol == 0) { + return RDataFactory.createDoubleVector(new double[]{}, true, new int[]{nrow, ncol}); } else { throw error(Message.X_NUMERIC); } @@ -74,43 +73,31 @@ public abstract class Diag extends RBuiltinNode.Arg3 { return RDataFactory.createDoubleVector(data, !RRuntime.isNA(x), new int[]{nrow, ncol}); } - @Specialization - protected Object diag(RAbstractComplexVector x, int nrow, int ncol) { + @Specialization(guards = "xAccess.supports(x)") + protected RAbstractVector diagCached(RAbstractVector x, int nrow, int ncol, + @Cached("x.access()") VectorAccess xAccess, + @Cached("createNew(xAccess.getType())") VectorAccess resultAccess, + @Cached("create()") VectorFactory factory) { int mn = checkX(x, nrow, ncol); - double[] data = new double[nrow * ncol * 2]; - int nx = x.getLength(); - for (int j = 0; j < mn; j++) { - RComplex value = x.getDataAt(j % nx); - int index = j * (nrow + 1) * 2; - data[index] = value.getRealPart(); - data[index + 1] = value.getImaginaryPart(); - } - return RDataFactory.createComplexVector(data, x.isComplete(), new int[]{nrow, ncol}); - } - - @Specialization - protected Object diag(RAbstractDoubleVector source, int nrow, int ncol) { - int mn = checkX(source, nrow, ncol); - - double[] data = new double[nrow * ncol]; - int nx = source.getLength(); - for (int j = 0; j < mn; j++) { - data[j * (nrow + 1)] = source.getDataAt(j % nx); + try (SequentialIterator xIter = xAccess.access(x)) { + RAbstractVector result = factory.createUninitializedVector(xAccess.getType(), nrow * ncol, new int[]{nrow, ncol}, null, null); + try (RandomIterator resultIter = resultAccess.randomAccess(result)) { + int resultIndex = 0; + for (int j = 0; j < mn; j++) { + xAccess.nextWithWrap(xIter); + resultAccess.setFromSameType(resultIter, resultIndex, xAccess, xIter); + resultIndex += nrow + 1; + } + } + result.setComplete(x.isComplete()); + return result; } - return RDataFactory.createDoubleVector(data, source.isComplete(), new int[]{nrow, ncol}); } - @Specialization - protected Object diag(RAbstractLogicalVector source, int nrow, int ncol) { - int mn = checkX(source, nrow, ncol); - - byte[] data = new byte[nrow * ncol]; - int nx = source.getLength(); - for (int j = 0; j < mn; j++) { - data[j * (nrow + 1)] = source.getDataAt(j % nx); - } - return RDataFactory.createLogicalVector(data, source.isComplete(), new int[]{nrow, ncol}); + @Specialization(replaces = "diagCached") + protected RAbstractVector diagGeneric(RAbstractVector x, int nrow, int ncol, + @Cached("create()") VectorFactory factory) { + return diagCached(x, nrow, ncol, x.slowPathAccess(), VectorAccess.createSlowPathNew(x.getRType()), factory); } - } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java index aa20ab830cb4c4a1ef9ff37b5afc90c34a03b4d4..c58f3020137ad9a68eaede21ba87a484355e5688 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Expression.java @@ -70,6 +70,7 @@ public abstract class Expression extends RBuiltinNode.Arg1 { } @Specialization + @TruffleBoundary protected Object doExpression(RPromise language) { return RDataFactory.createExpression(new Object[]{convert(language)}); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java index c1c66e7f6d09059fe7f3a70fcc8f35dc0e766857..972ed1ade43a577e5cdfd9f91ca678b2519c8708 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GetFunctions.java @@ -51,7 +51,6 @@ import com.oracle.truffle.r.nodes.function.RCallerHelper; import com.oracle.truffle.r.nodes.function.call.CallRFunctionCachedNode; import com.oracle.truffle.r.nodes.function.call.CallRFunctionCachedNodeGen; import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen; import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RCaller; @@ -146,7 +145,7 @@ public class GetFunctions { public static final class S4ToEnvNode extends CastNode { - @Child private GetS4DataSlot getS4Data = GetS4DataSlotNodeGen.create(RType.Environment); + @Child private GetS4DataSlot getS4Data = GetS4DataSlot.create(RType.Environment); @Override public Object execute(Object obj) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java index 05cbcbc30395a817ec2ee19a832c87018dced4ef..37d8da2fa8707921e44f38ef3b1093974fe2838c 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsNA.java @@ -27,46 +27,41 @@ import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; -import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode; +import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; 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.RList; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RTypedValue; -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.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; @ImportStatic(RRuntime.class) @RBuiltin(name = "is.na", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE) public abstract class IsNA extends RBuiltinNode.Arg1 { @Child private IsNA recursiveIsNA; - @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); + + @Child private VectorFactory factory = VectorFactory.create(); @Child private GetDimAttributeNode getDimsNode = GetDimAttributeNode.create(); - @Child private SetDimNamesAttributeNode setDimNamesNode = SetDimNamesAttributeNode.create(); + @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create(); - private final ConditionProfile nullDimNamesProfile = ConditionProfile.createBinaryProfile(); - static { Casts.noCasts(IsNA.class); } @@ -86,93 +81,21 @@ public abstract class IsNA extends RBuiltinNode.Arg1 { return RRuntime.asLogical(RRuntime.isNA(value)); } - @Specialization - protected RLogicalVector isNA(RAbstractIntVector vector) { - byte[] resultVector = new byte[vector.getLength()]; - for (int i = 0; i < vector.getLength(); i++) { - resultVector[i] = RRuntime.asLogical(RRuntime.isNA(vector.getDataAt(i))); - } - return createResult(resultVector, vector); - } - @Specialization protected byte isNA(double value) { return RRuntime.asLogical(RRuntime.isNAorNaN(value)); } - @Specialization - protected RLogicalVector isNA(RAbstractDoubleVector vector) { - byte[] resultVector = new byte[vector.getLength()]; - for (int i = 0; i < vector.getLength(); i++) { - resultVector[i] = RRuntime.asLogical(RRuntime.isNAorNaN(vector.getDataAt(i))); - } - return createResult(resultVector, vector); - } - - @Specialization - protected RLogicalVector isNA(RComplexVector vector) { - byte[] resultVector = new byte[vector.getLength()]; - for (int i = 0; i < vector.getLength(); i++) { - RComplex complex = vector.getDataAt(i); - resultVector[i] = RRuntime.asLogical(RRuntime.isNA(complex)); - } - return createResult(resultVector, vector); - } - @Specialization protected byte isNA(String value) { return RRuntime.asLogical(RRuntime.isNA(value)); } - @Specialization - protected RLogicalVector isNA(RStringVector vector) { - byte[] resultVector = new byte[vector.getLength()]; - for (int i = 0; i < vector.getLength(); i++) { - resultVector[i] = RRuntime.asLogical(RRuntime.isNA(vector.getDataAt(i))); - } - return createResult(resultVector, vector); - } - - @Specialization - protected RLogicalVector isNA(RList list) { - byte[] resultVector = new byte[list.getLength()]; - for (int i = 0; i < list.getLength(); i++) { - Object result = isNARecursive(list.getDataAt(i)); - byte isNAResult; - if (result instanceof Byte) { - isNAResult = (Byte) result; - } else if (result instanceof RLogicalVector) { - RLogicalVector vector = (RLogicalVector) result; - // result is false unless that element is a length-one atomic vector - // and the single element of that vector is regarded as NA - isNAResult = (vector.getLength() == 1) ? vector.getDataAt(0) : RRuntime.LOGICAL_FALSE; - } else { - throw fail("unhandled return type in isNA(list)"); - } - resultVector[i] = isNAResult; - } - return RDataFactory.createLogicalVector(resultVector, RDataFactory.COMPLETE_VECTOR); - } - - @TruffleBoundary - private static UnsupportedOperationException fail(String message) { - throw new UnsupportedOperationException(message); - } - @Specialization protected byte isNA(byte value) { return RRuntime.asLogical(RRuntime.isNA(value)); } - @Specialization - protected RLogicalVector isNA(RLogicalVector vector) { - byte[] resultVector = new byte[vector.getLength()]; - for (int i = 0; i < vector.getLength(); i++) { - resultVector[i] = (RRuntime.isNA(vector.getDataAt(i)) ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE); - } - return createResult(resultVector, vector); - } - @Specialization protected byte isNA(RComplex value) { return RRuntime.asLogical(RRuntime.isNA(value)); @@ -183,19 +106,62 @@ public abstract class IsNA extends RBuiltinNode.Arg1 { return RRuntime.LOGICAL_FALSE; } - @Specialization - protected RLogicalVector isNA(RRawVector vector) { - byte[] resultVector = new byte[vector.getLength()]; - for (int i = 0; i < vector.getLength(); i++) { - resultVector[i] = RRuntime.LOGICAL_FALSE; + private RLogicalVector isNAVector(RAbstractVector vector, VectorAccess access) { + try (SequentialIterator iter = access.access(vector)) { + byte[] data = new byte[access.getLength(iter)]; + while (access.next(iter)) { + boolean isNA; + switch (access.getType()) { + case Double: + isNA = access.na.checkNAorNaN(access.getDouble(iter)); + break; + case Character: + case Complex: + case Integer: + case Logical: + isNA = access.isNA(iter); + break; + case Raw: + isNA = false; + break; + case List: + Object result = isNARecursive(access.getListElement(iter)); + if (result instanceof Byte) { + isNA = ((byte) result) == RRuntime.LOGICAL_TRUE; + } else if (result instanceof RLogicalVector) { + RLogicalVector recVector = (RLogicalVector) result; + // result is false unless that element is a length-one atomic vector + // and the single element of that vector is regarded as NA + isNA = (recVector.getLength() == 1) ? recVector.getDataAt(0) == RRuntime.LOGICAL_TRUE : false; + } else { + throw RInternalError.shouldNotReachHere("unhandled return type in isNA(list)"); + } + break; + default: + throw RInternalError.shouldNotReachHere(); + + } + data[iter.getIndex()] = RRuntime.asLogical(isNA); + } + return factory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR, getDimsNode.getDimensions(vector), getNamesNode.getNames(vector), getDimNamesNode.getDimNames(vector)); } - return createResult(resultVector, vector); + } + + @Specialization(guards = "access.supports(vector)") + protected RLogicalVector isNACached(RAbstractVector vector, + @Cached("vector.access()") VectorAccess access) { + return isNAVector(vector, access); + } + + @Specialization(replaces = "isNACached") + protected RLogicalVector isNAGeneric(RAbstractVector vector) { + return isNAVector(vector, vector.slowPathAccess()); } @Specialization protected RLogicalVector isNA(RNull value) { warning(RError.Message.IS_NA_TO_NON_VECTOR, value.getRType().getName()); - return RDataFactory.createEmptyLogicalVector(); + return factory.createEmptyLogicalVector(); } @Specialization(guards = "isForeignObject(obj)") @@ -203,20 +169,9 @@ public abstract class IsNA extends RBuiltinNode.Arg1 { return RRuntime.LOGICAL_FALSE; } - // Note: all the primitive values have specialization, so we can only get RTypedValue in - // fallback @Fallback protected byte isNA(Object value) { - warning(RError.Message.IS_NA_TO_NON_VECTOR, value instanceof RTypedValue ? ((RTypedValue) value).getRType().getName() : value); + warning(RError.Message.IS_NA_TO_NON_VECTOR, Predef.typeName().apply(value)); return RRuntime.LOGICAL_FALSE; } - - private RLogicalVector createResult(byte[] data, RAbstractVector originalVector) { - RLogicalVector result = RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR, getDimsNode.getDimensions(originalVector), getNamesNode.getNames(originalVector)); - RList dimNames = getDimNamesNode.getDimNames(originalVector); - if (nullDimNamesProfile.profile(dimNames != null)) { - setDimNamesNode.setDimNames(result, dimNames); - } - return result; - } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java index 1c8e9a467c3778ce3db3195961695c17e40ca341..dee51d150d82e3b75710a984716eb785e812ae04 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsTypeFunctions.java @@ -41,6 +41,7 @@ import com.oracle.truffle.r.nodes.attributes.GetFixedAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetClassAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.GetDimAttributeNodeGen; +import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.helpers.InheritsCheckNode; import com.oracle.truffle.r.runtime.RError; @@ -59,6 +60,7 @@ import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RSymbol; +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; @@ -72,17 +74,14 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector; */ public class IsTypeFunctions { - protected abstract static class MissingAdapter extends RBuiltinNode.Arg1 { - - protected static Casts createCasts(Class<? extends MissingAdapter> extCls) { - Casts casts = new Casts(extCls); - casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x"); - return casts; - } + protected static Casts createCasts(Class<? extends RBuiltinNode> extCls) { + Casts casts = new Casts(extCls); + casts.arg("x").mustNotBeMissing(RError.Message.ARGUMENT_MISSING, "x"); + return casts; } @RBuiltin(name = "is.array", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE) - public abstract static class IsArray extends MissingAdapter { + public abstract static class IsArray extends RBuiltinNode.Arg1 { static { createCasts(IsArray.class); @@ -106,7 +105,7 @@ public class IsTypeFunctions { @ImportStatic(RRuntime.class) @RBuiltin(name = "is.recursive", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsRecursive extends MissingAdapter { + public abstract static class IsRecursive extends RBuiltinNode.Arg1 { static { createCasts(IsRecursive.class); @@ -144,9 +143,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.atomic", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsAtomic extends MissingAdapter { - - @Child private InheritsCheckNode inheritsFactorCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR); + public abstract static class IsAtomic extends RBuiltinNode.Arg1 { static { createCasts(IsAtomic.class); @@ -157,28 +154,19 @@ public class IsTypeFunctions { return RRuntime.LOGICAL_TRUE; } - @Specialization(guards = {"!isRList(arg)", "!isRExpression(arg)"}) - protected byte isAtomic(@SuppressWarnings("unused") RAbstractVector arg) { + @Specialization + protected byte isAtomic(@SuppressWarnings("unused") RAbstractAtomicVector arg) { return RRuntime.LOGICAL_TRUE; } - protected static boolean isNonListVector(Object value) { - return value instanceof Integer || value instanceof Double || value instanceof RComplex || value instanceof String || value instanceof RRaw || - (value instanceof RAbstractVector && !(value instanceof RListBase)); - } - - protected boolean isFactor(Object value) { - return inheritsFactorCheck.execute(value); - } - - @Specialization(guards = {"!isRMissing(value)", "!isRNull(value)", "!isFactor(value)", "!isNonListVector(value)"}) + @Fallback protected byte isType(@SuppressWarnings("unused") Object value) { return RRuntime.LOGICAL_FALSE; } } @RBuiltin(name = "is.call", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsCall extends MissingAdapter { + public abstract static class IsCall extends RBuiltinNode.Arg1 { static { Casts.noCasts(IsCall.class); @@ -196,7 +184,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.character", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsCharacter extends MissingAdapter { + public abstract static class IsCharacter extends RBuiltinNode.Arg1 { static { createCasts(IsCharacter.class); @@ -218,7 +206,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.complex", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsComplex extends MissingAdapter { + public abstract static class IsComplex extends RBuiltinNode.Arg1 { static { createCasts(IsComplex.class); @@ -240,7 +228,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.double", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsDouble extends MissingAdapter { + public abstract static class IsDouble extends RBuiltinNode.Arg1 { static { createCasts(IsDouble.class); @@ -262,7 +250,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.expression", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsExpression extends MissingAdapter { + public abstract static class IsExpression extends RBuiltinNode.Arg1 { static { createCasts(IsExpression.class); @@ -280,7 +268,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.function", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsFunction extends MissingAdapter { + public abstract static class IsFunction extends RBuiltinNode.Arg1 { static { createCasts(IsFunction.class); @@ -298,7 +286,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.integer", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsInteger extends MissingAdapter { + public abstract static class IsInteger extends RBuiltinNode.Arg1 { static { createCasts(IsInteger.class); @@ -320,7 +308,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.language", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsLanguage extends MissingAdapter { + public abstract static class IsLanguage extends RBuiltinNode.Arg1 { static { createCasts(IsLanguage.class); @@ -348,7 +336,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.list", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsList extends MissingAdapter { + public abstract static class IsList extends RBuiltinNode.Arg1 { static { createCasts(IsList.class); @@ -373,7 +361,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.logical", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsLogical extends MissingAdapter { + public abstract static class IsLogical extends RBuiltinNode.Arg1 { static { createCasts(IsLogical.class); @@ -395,7 +383,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.matrix", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE) - public abstract static class IsMatrix extends MissingAdapter { + public abstract static class IsMatrix extends RBuiltinNode.Arg1 { private final ConditionProfile isMatrixProfile = ConditionProfile.createBinaryProfile(); @Child private GetDimAttributeNode getDim = GetDimAttributeNodeGen.create(); @@ -416,7 +404,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.name", aliases = {"is.symbol"}, kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsName extends MissingAdapter { + public abstract static class IsName extends RBuiltinNode.Arg1 { static { createCasts(IsName.class); @@ -434,12 +422,18 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.numeric", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE) - public abstract static class IsNumeric extends MissingAdapter { + public abstract static class IsNumeric extends RBuiltinNode.Arg1 { static { createCasts(IsNumeric.class); } + @Child private InheritsCheckNode inheritsCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR); + + protected boolean isFactor(Object o) { + return inheritsCheck.execute(o); + } + @Specialization(guards = "!isFactor(value)") protected byte isType(@SuppressWarnings("unused") RAbstractIntVector value) { return RRuntime.LOGICAL_TRUE; @@ -459,20 +453,14 @@ public class IsTypeFunctions { return value instanceof Integer || value instanceof Double || value instanceof RAbstractIntVector || value instanceof RAbstractDoubleVector; } - @Specialization(guards = {"!isRMissing(value)", "!isAnyNumeric(value)"}) + @Fallback protected byte isType(@SuppressWarnings("unused") Object value) { return RRuntime.LOGICAL_FALSE; } - - @Child private InheritsCheckNode inheritsCheck = new InheritsCheckNode(RRuntime.CLASS_FACTOR); - - protected boolean isFactor(Object o) { - return inheritsCheck.execute(o); - } } @RBuiltin(name = "is.null", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsNull extends MissingAdapter { + public abstract static class IsNull extends RBuiltinNode.Arg1 { static { createCasts(IsNull.class); @@ -497,7 +485,7 @@ public class IsTypeFunctions { * {@code FALSE}. */ @RBuiltin(name = "is.object", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsObject extends MissingAdapter { + public abstract static class IsObject extends RBuiltinNode.Arg1 { @Child private GetClassAttributeNode getClassNode = GetClassAttributeNode.create(); @@ -519,7 +507,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.pairlist", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsPairList extends MissingAdapter { + public abstract static class IsPairList extends RBuiltinNode.Arg1 { static { createCasts(IsPairList.class); @@ -542,7 +530,7 @@ public class IsTypeFunctions { } @RBuiltin(name = "is.raw", kind = PRIMITIVE, parameterNames = {"x"}, behavior = PURE) - public abstract static class IsRaw extends MissingAdapter { + public abstract static class IsRaw extends RBuiltinNode.Arg1 { static { createCasts(IsRaw.class); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java index a0ccf139a825fec278a10995f7589705fa588b36..b1681c9175c0ecfe0cd9dd114104f0d67a80a4b5 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LaFunctions.java @@ -65,7 +65,6 @@ import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import com.oracle.truffle.r.runtime.data.nodes.GetDataCopy; import com.oracle.truffle.r.runtime.data.nodes.GetReadonlyData; import com.oracle.truffle.r.runtime.ffi.LapackRFFI; import com.oracle.truffle.r.runtime.ffi.RFFIFactory; @@ -751,7 +750,6 @@ public class LaFunctions { @Specialization protected Object doSvd(String ju, RAbstractDoubleVector x, RAbstractDoubleVector s, RAbstractDoubleVector u, RAbstractDoubleVector vt, - @Cached("create()") GetDataCopy.Double getDataCopyNode, @Cached("createCopyAllAttributes()") CopyAttributesNode copyAttrNode, @Cached("create()") GetDimAttributeNode getDimsNode) { @@ -767,10 +765,10 @@ public class LaFunctions { int[] iwork = new int[8 * Math.min(n, p)]; - double[] xvals = getDataCopyNode.execute(x); - double[] sdata = getDataCopyNode.execute(s); - double[] udata = getDataCopyNode.execute(u); - double[] vtdata = getDataCopyNode.execute(vt); + double[] xvals = x.materialize().getDataTemp(); + double[] sdata = s.materialize().getDataTemp(); + double[] udata = u.materialize().getDataTemp(); + double[] vtdata = vt.materialize().getDataTemp(); double[] tmp = new double[1]; int info = dgesddNode.execute(ju.charAt(0), n, p, xvals, n, sdata, udata, ldu, vtdata, ldvt, tmp, -1, iwork); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java index 161972a2025762f48eb886d98d443d34169fd7e2..3630833bce79cfadd30c24afa80a8f1b8ca603ea 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Matrix.java @@ -35,6 +35,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RVector; @@ -68,8 +69,8 @@ public abstract class Matrix extends RBuiltinNode.Arg7 { static { Casts casts = new Casts(Matrix.class); casts.arg("data").asVector().mustBe(instanceOf(RAbstractVector.class)); - casts.arg("nrow").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT); - casts.arg("ncol").asIntegerVector().findFirst(RError.Message.NON_NUMERIC_MATRIX_EXTENT); + casts.arg("nrow").asIntegerVector().findFirst(Message.NON_NUMERIC_MATRIX_EXTENT).mustNotBeNA(Message.INVALID_LARGE_NA_VALUE, "nrow"); + casts.arg("ncol").asIntegerVector().findFirst(Message.NON_NUMERIC_MATRIX_EXTENT).mustNotBeNA(Message.INVALID_LARGE_NA_VALUE, "ncol"); casts.arg("byrow").asLogicalVector().findFirst().map(toBoolean()); casts.arg("dimnames").allowNull().mustBe(instanceOf(RAbstractListVector.class)); casts.arg("missingNr").asLogicalVector().findFirst().map(toBoolean()); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java index 53a91f171580ab9796ecd04558e257dbee5a5ac3..a4f4732f9fe0504cdf94bfe4348ce04350b2ea76 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Mean.java @@ -26,81 +26,79 @@ import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE_SUMMARY; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.profiles.BranchProfile; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RDataFactory; -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.ops.BinaryArithmetic; +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; +@ImportStatic(RType.class) @RBuiltin(name = "mean", kind = INTERNAL, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE_SUMMARY) public abstract class Mean extends RBuiltinNode.Arg1 { - private final BranchProfile emptyProfile = BranchProfile.create(); - - @Child private BinaryArithmetic add = BinaryArithmetic.ADD.createOperation(); - @Child private BinaryArithmetic div = BinaryArithmetic.DIV.createOperation(); - static { Casts.noCasts(Mean.class); } - @Specialization - protected double mean(RAbstractDoubleVector x) { - if (x.getLength() == 0) { - emptyProfile.enter(); - return Double.NaN; + @Specialization(guards = {"access.supports(x)", "access.getType() != Complex"}) + protected double meanDoubleCached(RAbstractVector x, + @Cached("x.access()") VectorAccess access, + @Cached("createBinaryProfile()") ConditionProfile emptyProfile) { + try (SequentialIterator iter = access.access(x)) { + if (emptyProfile.profile(!access.next(iter))) { + return Double.NaN; + } + double sum = 0; + do { + double value = access.getDouble(iter); + if (access.na.checkNAorNaN(value)) { + return value; + } + sum += value; + } while (access.next(iter)); + return sum / access.getLength(iter); } - double sum = x.getDataAt(0); - for (int k = 1; k < x.getLength(); k++) { - sum = add.op(sum, x.getDataAt(k)); - } - return div.op(sum, x.getLength()); } - @Specialization - protected double mean(RAbstractIntVector x) { - if (x.getLength() == 0) { - emptyProfile.enter(); - return Double.NaN; - } - double sum = x.getDataAt(0); - for (int k = 1; k < x.getLength(); k++) { - sum = add.op(sum, x.getDataAt(k)); - } - return div.op(sum, x.getLength()); + @Specialization(replaces = "meanDoubleCached", guards = "x.getRType() != Complex") + protected double meanDoubleGeneric(RAbstractVector x, + @Cached("createBinaryProfile()") ConditionProfile emptyProfile) { + return meanDoubleCached(x, x.slowPathAccess(), emptyProfile); } - @Specialization - protected double mean(RAbstractLogicalVector x) { - if (x.getLength() == 0) { - emptyProfile.enter(); - return Double.NaN; - } - double sum = x.getDataAt(0); - for (int k = 1; k < x.getLength(); k++) { - sum = add.op(sum, x.getDataAt(k)); + @Specialization(guards = {"access.supports(x)", "access.getType() == Complex"}) + protected RComplex meanComplexCached(RAbstractVector x, + @Cached("x.access()") VectorAccess access, + @Cached("createBinaryProfile()") ConditionProfile emptyProfile) { + try (SequentialIterator iter = access.access(x)) { + if (emptyProfile.profile(!access.next(iter))) { + return RComplex.valueOf(Double.NaN, Double.NaN); + } + double sumR = 0; + double sumI = 0; + do { + double valueR = access.getComplexR(iter); + double valueI = access.getComplexI(iter); + if (access.na.check(valueR, valueI)) { + return RComplex.valueOf(valueR, valueI); + } + sumR += valueR; + sumI += valueI; + } while (access.next(iter)); + int length = access.getLength(iter); + return RComplex.valueOf(sumR / length, sumI / length); } - return div.op(sum, x.getLength()); } - @Specialization - protected RComplex mean(RAbstractComplexVector x) { - if (x.getLength() == 0) { - emptyProfile.enter(); - return RDataFactory.createComplex(Double.NaN, Double.NaN); - } - RComplex sum = x.getDataAt(0); - RComplex comp; - for (int k = 1; k < x.getLength(); k++) { - comp = x.getDataAt(k); - sum = add.op(sum.getRealPart(), sum.getImaginaryPart(), comp.getRealPart(), comp.getImaginaryPart()); - } - return div.op(sum.getRealPart(), sum.getImaginaryPart(), x.getLength(), 0); + @Specialization(replaces = "meanComplexCached", guards = "x.getRType() == Complex") + protected RComplex meanComplexGeneric(RAbstractVector x, + @Cached("createBinaryProfile()") ConditionProfile emptyProfile) { + return meanComplexCached(x, x.slowPathAccess(), emptyProfile); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java index da39fe9bdec0bf28a7259cf9f31fb90fe5b65302..2ca65bc6427b9c391f9faf31de90e40cd2c9bb8e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Prod.java @@ -14,33 +14,30 @@ import static com.oracle.truffle.r.runtime.RDispatch.SUMMARY_GROUP_GENERIC; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE_SUMMARY; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; -import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RNull; -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.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; import com.oracle.truffle.r.runtime.ops.BinaryArithmetic; -import com.oracle.truffle.r.runtime.ops.na.NACheck; +@ImportStatic(RType.class) @RBuiltin(name = "prod", kind = PRIMITIVE, parameterNames = {"...", "na.rm"}, dispatch = SUMMARY_GROUP_GENERIC, behavior = PURE_SUMMARY) public abstract class Prod extends RBuiltinNode.Arg2 { - // TODO: handle multiple arguments, handle na.rm - static { - Casts.noCasts(Prod.class); + Casts casts = new Casts(Prod.class); + casts.arg("na.rm").asLogicalVector().findFirst(RRuntime.LOGICAL_FALSE).map(Predef.toBoolean()); } @Override @@ -48,139 +45,154 @@ public abstract class Prod extends RBuiltinNode.Arg2 { return new Object[]{RArgsValuesAndNames.EMPTY, RRuntime.LOGICAL_FALSE}; } - @Child private Prod prodRecursive; - - public abstract Object executeObject(Object x); - @Child private BinaryArithmetic prod = BinaryArithmetic.MULTIPLY.createOperation(); - @Specialization - protected Object prod(RArgsValuesAndNames args) { - int argsLen = args.getLength(); - if (argsLen == 0) { - return 1d; + @ExplodeLoop + protected static boolean supports(RArgsValuesAndNames args, VectorAccess[] argAccess) { + if (args.getLength() != argAccess.length) { + return false; } - if (prodRecursive == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - prodRecursive = insert(ProdNodeGen.create()); + for (int i = 0; i < argAccess.length; i++) { + if (!argAccess[i].supports(args.getArgument(i))) { + return false; + } } - Object ret = 1d; - if (argsLen > 0) { - double prodReal; - double prodImg; - boolean complex; - if (ret instanceof RComplex) { - RComplex c = (RComplex) ret; - prodReal = c.getRealPart(); - prodImg = c.getImaginaryPart(); - complex = true; - } else { - prodReal = (Double) ret; - prodImg = 0d; - complex = false; + return true; + } + + protected static VectorAccess[] createAccess(RArgsValuesAndNames args, RType topmostType) { + VectorAccess[] result = new VectorAccess[args.getLength()]; + for (int i = 0; i < result.length; i++) { + VectorAccess access = VectorAccess.create(args.getArgument(i)); + if (access == null) { + return null; } - for (int i = 0; i < argsLen; i++) { - Object aProd = prodRecursive.executeObject(args.getArgument(i)); - double aProdReal; - double aProdImg; - if (aProd instanceof RComplex) { - RComplex c = (RComplex) aProd; - if (RRuntime.isNA(c)) { - return c; - } - aProdReal = c.getRealPart(); - aProdImg = c.getImaginaryPart(); - complex = true; - } else { - aProdReal = (Double) aProd; - aProdImg = 0d; - if (RRuntime.isNA(aProdReal)) { - return aProd; - } - } - if (complex) { - RComplex c = prod.op(prodReal, prodImg, aProdReal, aProdImg); - prodReal = c.getRealPart(); - prodImg = c.getImaginaryPart(); - } else { - prodReal = prod.op(prodReal, aProdReal); - } + RType type = access.getType(); + if (type != RType.Null && type != RType.Logical && type != RType.Integer && type != RType.Double && type != topmostType) { + return null; } - ret = complex ? RComplex.valueOf(prodReal, prodImg) : prodReal; + result[i] = access; } - return ret; + return result; } - private final ValueProfile intVecProfile = ValueProfile.createClassProfile(); - private final NACheck naCheck = NACheck.create(); - - @Specialization - protected double prod(RAbstractDoubleVector x) { - RAbstractDoubleVector profiledVec = intVecProfile.profile(x); - double product = 1; - naCheck.enable(x); - for (int k = 0; k < profiledVec.getLength(); k++) { - double value = profiledVec.getDataAt(k); - if (naCheck.check(value)) { - return RRuntime.DOUBLE_NA; + @Specialization(guards = {"argAccess != null", "supports(args, argAccess)", "naRm == cachedNaRm"}) + @ExplodeLoop + protected double prodDoubleCached(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean naRm, + @Cached("naRm") boolean cachedNaRm, + @Cached("createAccess(args, Double)") VectorAccess[] argAccess) { + double value = 1; + for (int i = 0; i < argAccess.length; i++) { + VectorAccess access = argAccess[i]; + double element = prodDouble(args.getArgument(i), access, cachedNaRm); + if (!cachedNaRm && access.na.check(element)) { + return element; } - product = prod.op(product, value); + value *= element; } - return product; + return value; } - @Specialization - protected double prod(RAbstractIntVector x) { - RAbstractIntVector profiledVec = intVecProfile.profile(x); - double product = 1; - naCheck.enable(x); - for (int k = 0; k < profiledVec.getLength(); k++) { - int data = profiledVec.getDataAt(k); - if (naCheck.check(data)) { - return RRuntime.DOUBLE_NA; + @Specialization(guards = {"argAccess != null", "supports(args, argAccess)", "naRm == cachedNaRm"}) + @ExplodeLoop + protected RComplex prodComplexCached(RArgsValuesAndNames args, @SuppressWarnings("unused") boolean naRm, + @Cached("naRm") boolean cachedNaRm, + @Cached("createAccess(args, Complex)") VectorAccess[] argAccess) { + RComplex value = RComplex.valueOf(1, 0); + for (int i = 0; i < argAccess.length; i++) { + VectorAccess access = argAccess[i]; + RComplex element = prodComplex(args.getArgument(i), access, cachedNaRm); + if (!cachedNaRm && access.na.check(element)) { + return element; } - product = prod.op(product, data); + value = prod.op(value.getRealPart(), value.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart()); } - return product; + return value; } - @Specialization - protected double prod(RAbstractLogicalVector x) { - RAbstractLogicalVector profiledVec = intVecProfile.profile(x); - double product = 1; - naCheck.enable(x); - for (int k = 0; k < profiledVec.getLength(); k++) { - byte value = profiledVec.getDataAt(k); - if (naCheck.check(value)) { - return RRuntime.DOUBLE_NA; + @Specialization(replaces = {"prodDoubleCached", "prodComplexCached"}) + protected Object prodGeneric(RArgsValuesAndNames args, boolean naRm) { + int length = args.getLength(); + double value = 1; + int i = 0; + for (; i < length; i++) { + Object arg = args.getArgument(i); + VectorAccess access = VectorAccess.createSlowPath(arg); + if (access == null) { + break; + } + RType type = access.getType(); + if (type != RType.Null && type != RType.Logical && type != RType.Integer && type != RType.Double) { + break; + } + double element = prodDouble(arg, access, naRm); + if (!naRm && access.na.check(element)) { + return element; } - product = prod.op(product, value); + value *= element; } - return product; + if (i == length) { + return value; + } + RComplex complexValue = RComplex.valueOf(1, 0); + for (; i < length; i++) { + Object arg = args.getArgument(i); + VectorAccess access = VectorAccess.createSlowPath(arg); + if (access == null) { + break; + } + RType type = access.getType(); + if (!type.isNumeric() && type != RType.Null) { + break; + } + RComplex element = prodComplex(arg, access, naRm); + if (!naRm && access.na.check(element)) { + return element; + } + complexValue = prod.op(complexValue.getRealPart(), complexValue.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart()); + } + if (i == length) { + return complexValue; + } + throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(args.getArgument(i))); } - @Specialization - protected RComplex prod(RAbstractComplexVector x) { - RAbstractComplexVector profiledVec = intVecProfile.profile(x); - RComplex product = RDataFactory.createComplexRealOne(); - naCheck.enable(x); - for (int k = 0; k < profiledVec.getLength(); k++) { - RComplex a = profiledVec.getDataAt(k); - if (naCheck.check(a)) { - return a; + protected static double prodDouble(Object v, VectorAccess access, boolean naRm) { + try (SequentialIterator iter = access.access(v)) { + double value = 1; + while (access.next(iter)) { + double element = access.getDouble(iter); + if (access.na.check(element)) { + if (!naRm) { + return RRuntime.DOUBLE_NA; + } + } else { + value *= element; + } } - product = prod.op(product.getRealPart(), product.getImaginaryPart(), a.getRealPart(), a.getImaginaryPart()); + return value; } - return product; } - @Specialization - protected double prod(@SuppressWarnings("unused") RNull n) { - return 1d; + protected RComplex prodComplex(Object v, VectorAccess access, boolean naRm) { + try (SequentialIterator iter = access.access(v)) { + RComplex value = RComplex.valueOf(1, 0); + while (access.next(iter)) { + RComplex element = access.getComplex(iter); + if (access.na.check(element)) { + if (!naRm) { + return element; + } + } else { + value = prod.op(value.getRealPart(), value.getImaginaryPart(), element.getRealPart(), element.getImaginaryPart()); + } + } + return value; + } } @Fallback - protected Object prod(Object o) { - throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(o)); + protected Object prod(Object v, @SuppressWarnings("unused") Object naRm) { + throw error(RError.Message.INVALID_TYPE_ARGUMENT, Predef.typeName().apply(v)); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java index 9395c6682ce00d2918381fb53a963329567b0bf6..f269495c60854adbcf3695aa66ae4d1c7fa398e0 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Range.java @@ -65,8 +65,8 @@ public abstract class Range extends RBuiltinNode.Arg3 { @Specialization(guards = "args.getLength() == 1") protected RVector<?> rangeLengthOne(RArgsValuesAndNames args, boolean naRm, boolean finite) { - Object min = minReduce.executeReduce(args.getArgument(0), naRm, finite); - Object max = maxReduce.executeReduce(args.getArgument(0), naRm, finite); + Object min = minReduce.executeReduce(args.getArgument(0), naRm || finite, finite); + Object max = maxReduce.executeReduce(args.getArgument(0), naRm || finite, finite); return createResult(min, max); } @@ -84,8 +84,8 @@ public abstract class Range extends RBuiltinNode.Arg3 { protected RVector<?> range(RArgsValuesAndNames args, boolean naRm, boolean finite, @Cached("create()") Combine combine) { Object combined = combine.executeCombine(args, false); - Object min = minReduce.executeReduce(combined, naRm, finite); - Object max = maxReduce.executeReduce(combined, naRm, finite); + Object min = minReduce.executeReduce(combined, naRm || finite, finite); + Object max = maxReduce.executeReduce(combined, naRm || finite, finite); return createResult(min, max); } } 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()); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java index 9ece548f64e888b27287187d3d912401c354872f..0fade482ee9484506923c2d4d37feac2bc06bd62 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatInternal.java @@ -28,29 +28,19 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; -import java.util.function.IntFunction; - +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.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.builtins.RBuiltin; -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; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -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.RDataFactory.VectorFactory; +import com.oracle.truffle.r.runtime.data.RVector; 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; @RBuiltin(name = "rep.int", kind = INTERNAL, parameterNames = {"x", "times"}, behavior = PURE) public abstract class RepeatInternal extends RBuiltinNode.Arg2 { @@ -64,136 +54,70 @@ public abstract class RepeatInternal extends RBuiltinNode.Arg2 { RError.Message.INVALID_VALUE, "times"); } - @FunctionalInterface - private interface ArrayUpdateFunction<ValueT, ArrayT> { - void update(ArrayT array, int pos, ValueT value, int index); - } + private RAbstractVector performRep(RAbstractVector value, RAbstractIntVector times, VectorFactory factory, VectorAccess valueAccess, VectorAccess timesAccess, VectorAccess resultAccess) { + try (SequentialIterator valueIter = valueAccess.access(value); SequentialIterator timesIter = timesAccess.access(times)) { + int valueLength = valueAccess.getLength(valueIter); + int timesLength = timesAccess.getLength(timesIter); - @FunctionalInterface - private interface CreateResultFunction<ResultT, ArrayT> { - ResultT create(ArrayT array, boolean complete); - } - - private <ValueT extends RAbstractVector, ResultT extends ValueT, ArrayT> ResultT repInt(ValueT value, RAbstractIntVector times, IntFunction<ArrayT> arrayConstructor, - ArrayUpdateFunction<ValueT, ArrayT> arrayUpdate, CreateResultFunction<ResultT, ArrayT> createResult) { - ArrayT result; - int timesLength = times.getLength(); - int valueLength = value.getLength(); - if (timesOneProfile.profile(timesLength == 1)) { - int timesValue = times.getDataAt(0); - if (timesValue < 0) { - throw error(RError.Message.INVALID_VALUE, "times"); - } - int count = timesValue * valueLength; - result = arrayConstructor.apply(count); - int pos = 0; - for (int i = 0; i < timesValue; i++) { - for (int j = 0; j < valueLength; j++) { - arrayUpdate.update(result, pos++, value, j); - } - } - } else if (timesLength == valueLength) { - int count = 0; - for (int i = 0; i < timesLength; i++) { - int data = times.getDataAt(i); - if (data < 0) { + RVector<?> result; + if (timesOneProfile.profile(timesLength == 1)) { + timesAccess.next(timesIter); + int timesValue = timesAccess.getInt(timesIter); + if (timesValue < 0) { throw error(RError.Message.INVALID_VALUE, "times"); } - count += data; - } - result = arrayConstructor.apply(count); - int pos = 0; - for (int i = 0; i < valueLength; i++) { - int num = times.getDataAt(i); - for (int j = 0; j < num; j++) { - arrayUpdate.update(result, pos++, value, i); - } - } - } else { - throw error(RError.Message.INVALID_VALUE, "times"); - } - return createResult.create(result, value.isComplete()); - } - - @Specialization - protected RDoubleVector repInt(RAbstractDoubleVector value, RAbstractIntVector times) { - return repInt(value, times, double[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createDoubleVector); - } - - @Specialization - protected RIntVector repInt(RAbstractIntVector value, RAbstractIntVector times) { - return repInt(value, times, int[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createIntVector); - } - - @Specialization - protected RLogicalVector repInt(RAbstractLogicalVector value, RAbstractIntVector times) { - return repInt(value, times, byte[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createLogicalVector); - } - - @Specialization - protected RStringVector repInt(RAbstractStringVector value, RAbstractIntVector times) { - return repInt(value, times, String[]::new, (array, pos, val, index) -> array[pos] = val.getDataAt(index), RDataFactory::createStringVector); - } - - @Specialization - protected RRawVector repInt(RAbstractRawVector value, RAbstractIntVector times) { - return repInt(value, times, byte[]::new, (array, pos, val, index) -> array[pos] = val.getRawDataAt(index), (array, complete) -> RDataFactory.createRawVector(array)); - } - - @Specialization - protected RComplexVector repComplex(RAbstractComplexVector value, RAbstractIntVector times) { - int timesLength = times.getLength(); - int valueLength = value.getLength(); - double[] resultArray; - if (timesOneProfile.profile(timesLength == 1)) { - int timesValue = times.getDataAt(0); - if (timesValue < 0) { - throw error(RError.Message.INVALID_VALUE, "times"); - } - resultArray = new double[(timesValue * valueLength) << 1]; - int pos = 0; - for (int i = 0; i < timesValue; i++) { - for (int j = 0; j < valueLength; j++) { - RComplex complex = value.getDataAt(j); - resultArray[pos++] = complex.getRealPart(); - resultArray[pos++] = complex.getImaginaryPart(); + result = factory.createVector(valueAccess.getType(), timesValue * valueLength, false); + try (SequentialIterator resultIter = resultAccess.access(result)) { + for (int i = 0; i < timesValue; i++) { + while (valueAccess.next(valueIter)) { + resultAccess.next(resultIter); + resultAccess.setFromSameType(resultIter, valueAccess, valueIter); + } + valueAccess.reset(valueIter); + } } - } - } else if (timesLength == valueLength) { - int count = 0; - for (int i = 0; i < timesLength; i++) { - int data = times.getDataAt(i); - if (data < 0) { - throw error(RError.Message.INVALID_VALUE, "times"); + } else if (timesLength == valueLength) { + int count = 0; + while (timesAccess.next(timesIter)) { + int num = timesAccess.getInt(timesIter); + if (num < 0) { + throw error(RError.Message.INVALID_VALUE, "times"); + } + count += num; } - count += data; - } - resultArray = new double[count << 1]; - int pos = 0; - for (int i = 0; i < valueLength; i++) { - int num = times.getDataAt(i); - RComplex complex = value.getDataAt(i); - for (int j = 0; j < num; j++) { - resultArray[pos++] = complex.getRealPart(); - resultArray[pos++] = complex.getImaginaryPart(); + result = factory.createVector(valueAccess.getType(), count, false); + + timesAccess.reset(timesIter); + try (SequentialIterator resultIter = resultAccess.access(result)) { + while (timesAccess.next(timesIter) && valueAccess.next(valueIter)) { + int num = timesAccess.getInt(timesIter); + for (int i = 0; i < num; i++) { + resultAccess.next(resultIter); + resultAccess.setFromSameType(resultIter, valueAccess, valueIter); + } + } } + } else { + throw error(RError.Message.INVALID_VALUE, "times"); } - } else { - throw error(RError.Message.INVALID_VALUE, "times"); + result.setComplete(!valueAccess.na.isEnabled()); + return result; } - return RDataFactory.createComplexVector(resultArray, value.isComplete()); } - @Specialization - protected RList repList(RList value, int times) { - int oldLength = value.getLength(); - int length = value.getLength() * times; - Object[] array = new Object[length]; - for (int i = 0; i < times; i++) { - for (int j = 0; j < oldLength; j++) { - array[i * oldLength + j] = value.getDataAt(j); - } - } - return RDataFactory.createList(array); + @Specialization(guards = {"valueAccess.supports(value)", "timesAccess.supports(times)"}) + protected RAbstractVector repCached(RAbstractVector value, RAbstractIntVector times, + @Cached("create()") VectorFactory factory, + @Cached("value.access()") VectorAccess valueAccess, + @Cached("times.access()") VectorAccess timesAccess, + @Cached("createNew(value.getRType())") VectorAccess resultAccess) { + return performRep(value, times, factory, valueAccess, timesAccess, resultAccess); + } + + @Specialization(replaces = "repCached") + @TruffleBoundary + protected RAbstractVector repGeneric(RAbstractVector value, RAbstractIntVector times, + @Cached("create()") VectorFactory factory) { + return performRep(value, times, factory, value.slowPathAccess(), times.slowPathAccess(), VectorAccess.createSlowPathNew(value.getRType())); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java index cf0a608ef11441a88109cc56e1580643c41c4d5a..a66473e331cc373a18fa761822dd8e71279e0e4f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/RepeatLength.java @@ -12,40 +12,44 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.abstractVectorValue; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.notIntNA; -import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte0; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.instanceOf; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.singleElement; import static com.oracle.truffle.r.runtime.builtins.RBehavior.PURE; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import java.util.Arrays; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.builtins.RBuiltin; 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.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.RDoubleVector; +import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RRawVector; import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +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; @RBuiltin(name = "rep_len", kind = INTERNAL, parameterNames = {"x", "length.out"}, behavior = PURE) public abstract class RepeatLength extends RBuiltinNode.Arg2 { static { Casts casts = new Casts(RepeatLength.class); - casts.arg("x").allowNull().mustBe(abstractVectorValue(), RError.Message.ATTEMPT_TO_REPLICATE_NO_VECTOR); - // with default error message, SHOW_CALLER does not work - casts.arg("length.out").defaultError(RError.Message.INVALID_VALUE, "length.out").mustNotBeNull().asIntegerVector().mustBe(size(1)).findFirst().mustBe(notIntNA()); + casts.arg("x").allowNull().mustBe(abstractVectorValue().or(instanceOf(RExpression.class)), RError.Message.ATTEMPT_TO_REPLICATE_NO_VECTOR); + casts.arg("length.out").defaultError(RError.Message.INVALID_VALUE, "length.out").mustNotBeNull().asIntegerVector().mustBe(singleElement()).findFirst().mustNotBeNA().mustBe(gte0()); } @Specialization @@ -106,72 +110,33 @@ public abstract class RepeatLength extends RBuiltinNode.Arg2 { return RDataFactory.createLogicalVector(array, value != RRuntime.LOGICAL_NA); } - // - // Specialization for vector values - // - @Specialization - protected RIntVector repLen(RAbstractIntVector value, int length) { - int[] array = new int[length]; - for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) { - array[i] = value.getDataAt(j); + @Specialization(guards = "xAccess.supports(x)") + protected RAbstractVector repLenCached(RAbstractVector x, int length, + @Cached("x.access()") VectorAccess xAccess, + @Cached("createNew(xAccess.getType())") VectorAccess resultAccess, + @Cached("createBinaryProfile()") ConditionProfile emptyProfile, + @Cached("create()") VectorFactory factory) { + try (SequentialIterator xIter = xAccess.access(x)) { + if (emptyProfile.profile(xAccess.getLength(xIter) == 0)) { + return factory.createVector(xAccess.getType(), length, true); + } + RAbstractVector result = factory.createVector(xAccess.getType(), length, false); + try (SequentialIterator resultIter = resultAccess.access(result)) { + while (resultAccess.next(resultIter)) { + xAccess.nextWithWrap(xIter); + resultAccess.setFromSameType(resultIter, xAccess, xIter); + } + } + result.setComplete(x.isComplete()); + return result; } - return RDataFactory.createIntVector(array, value.isComplete()); } - @Specialization - protected RDoubleVector repLen(RDoubleVector value, int length) { - double[] array = new double[length]; - for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) { - array[i] = value.getDataAt(j); - } - return RDataFactory.createDoubleVector(array, value.isComplete()); + @Specialization(replaces = "repLenCached") + protected RAbstractVector repLenGeneric(RAbstractVector x, int length, + @Cached("createBinaryProfile()") ConditionProfile emptyProfile, + @Cached("create()") VectorFactory factory) { + return repLenCached(x, length, x.slowPathAccess(), VectorAccess.createSlowPathNew(x.getRType()), emptyProfile, factory); } - @Specialization - protected RStringVector repLen(RStringVector vectorToRepeat, int length) { - String[] result = new String[length]; - int vectorToRepeatLength = vectorToRepeat.getLength(); - for (int i = 0; i < length; i++) { - result[i] = vectorToRepeat.getDataAt(i % vectorToRepeatLength); - } - return RDataFactory.createStringVector(result, vectorToRepeat.isComplete()); - } - - @Specialization - protected RRawVector repLen(RRawVector value, int length) { - byte[] array = new byte[length]; - for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) { - array[i] = value.getRawDataAt(j); - } - return RDataFactory.createRawVector(array); - } - - @Specialization - protected RComplexVector repLen(RComplexVector value, int length) { - final int resultLength = length * 2; - double[] array = new double[resultLength]; - for (int i = 0, j = 0; i < resultLength; i += 2, j = Utils.incMod(j, value.getLength())) { - array[i] = value.getDataAt(j).getRealPart(); - array[i + 1] = value.getDataAt(j).getImaginaryPart(); - } - return RDataFactory.createComplexVector(array, value.isComplete()); - } - - @Specialization - protected RLogicalVector repLen(RLogicalVector value, int length) { - byte[] array = new byte[length]; - for (int i = 0, j = 0; i < length; i++, j = Utils.incMod(j, value.getLength())) { - array[i] = value.getDataAt(j); - } - return RDataFactory.createLogicalVector(array, value.isComplete()); - } - - @Specialization - protected RList repLen(RList list, int length) { - Object[] data = new Object[length]; - for (int i = 0; i < length; i++) { - data[i] = list.getDataAt(i % list.getLength()); - } - return RDataFactory.createList(data); - } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java index 407ce9faac3f31777368b02558b5ce92eb6a1b82..a3450d32ad3725485fdf7d5f1578e8245b392bcb 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Round.java @@ -31,6 +31,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; @@ -52,6 +53,8 @@ public abstract class Round extends RBuiltinNode.Arg2 { @Child private RoundArithmetic roundOp = new RoundArithmetic(); + private final ConditionProfile zeroDigitProfile = ConditionProfile.createBinaryProfile(); + private final NACheck check = NACheck.create(); @Override @@ -83,6 +86,13 @@ public abstract class Round extends RBuiltinNode.Arg2 { return check.check(x) ? RRuntime.DOUBLE_NA : x; } + @Specialization + protected double roundDigits(double x, double digits) { + check.enable(x); + int digitsInt = (int) Math.round(digits); + return check.check(x) ? RRuntime.DOUBLE_NA : zeroDigitProfile.profile(digitsInt == 0) ? roundOp.op(x) : roundOp.opd(x, digitsInt); + } + @Specialization protected RDoubleVector round(RAbstractLogicalVector x, @SuppressWarnings("unused") double digits) { double[] data = new double[x.getLength()]; @@ -105,43 +115,18 @@ public abstract class Round extends RBuiltinNode.Arg2 { return RDataFactory.createDoubleVector(data, check.neverSeenNA()); } - @Specialization(guards = "isZero(digits)") - protected double round(double x, @SuppressWarnings("unused") double digits) { - check.enable(x); - return check.check(x) ? RRuntime.DOUBLE_NA : roundOp.op(x); - } - protected double roundDigits(double x, int digits) { - check.enable(x); - return check.check(x) ? RRuntime.DOUBLE_NA : roundOp.opd(x, digits); - } - - @Specialization(guards = "!isZero(digits)") - protected double roundDigits(double x, double digits) { - return roundDigits(x, (int) Math.round(digits)); + return check.check(x) ? RRuntime.DOUBLE_NA : zeroDigitProfile.profile(digits == 0) ? roundOp.op(x) : roundOp.opd(x, digits); } - @Specialization(guards = "isZero(digits)") + @Specialization protected RDoubleVector round(RAbstractDoubleVector x, double digits) { double[] result = new double[x.getLength()]; check.enable(x); + int digitsInt = (int) Math.round(digits); for (int i = 0; i < x.getLength(); i++) { double value = x.getDataAt(i); - result[i] = check.check(value) ? RRuntime.DOUBLE_NA : round(value, digits); - } - RDoubleVector ret = RDataFactory.createDoubleVector(result, check.neverSeenNA()); - ret.copyAttributesFrom(x); - return ret; - } - - @Specialization(guards = "!isZero(dDigits)") - protected RDoubleVector roundDigits(RAbstractDoubleVector x, double dDigits) { - double[] result = new double[x.getLength()]; - int digits = (int) Math.round(dDigits); - check.enable(x); - for (int i = 0; i < x.getLength(); i++) { - double value = x.getDataAt(i); - result[i] = check.check(value) ? RRuntime.DOUBLE_NA : roundDigits(value, digits); + result[i] = check.check(value) ? RRuntime.DOUBLE_NA : zeroDigitProfile.profile(digitsInt == 0) ? roundOp.op(value) : roundOp.opd(value, digitsInt); } RDoubleVector ret = RDataFactory.createDoubleVector(result, check.neverSeenNA()); ret.copyAttributesFrom(x); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java index c760f844bb6b9edefe7a99821f79213d08e2009f..3a288c89a58e532a5082356475c88742234dad6e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Split.java @@ -27,24 +27,23 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.INTERNAL; import java.util.Arrays; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.builtin.base.SplitNodeGen.GetSplitNamesNodeGen; import com.oracle.truffle.r.nodes.helpers.RFactorNodes; -import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RRawVector; import com.oracle.truffle.r.runtime.data.RStringVector; -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.RAbstractListVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; -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.VectorReadAccess; +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.nodes.RBaseNode; /** * The {@code split} internal. Internal version of 'split' is invoked from 'split.default' function @@ -60,11 +59,7 @@ import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess; public abstract class Split extends RBuiltinNode.Arg2 { @Child private RFactorNodes.GetLevels getLevelNode = new RFactorNodes.GetLevels(); - @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); - - @SuppressWarnings("unused") private final ConditionProfile noStringLevels = ConditionProfile.createBinaryProfile(); - private final ConditionProfile namesProfile = ConditionProfile.createBinaryProfile(); - @Child private VectorReadAccess.Int factorAccess = VectorReadAccess.Int.create(); + @Child private GetSplitNames getSplitNames = GetSplitNamesNodeGen.create(); private static final int INITIAL_SIZE = 5; private static final int SCALE_FACTOR = 2; @@ -73,238 +68,234 @@ public abstract class Split extends RBuiltinNode.Arg2 { Casts.noCasts(Split.class); } - @Specialization - protected RList split(RAbstractListVector x, RAbstractIntVector f) { - Object fStore = factorAccess.getDataStore(f); - RStringVector names = getLevelNode.execute(f); - final int nLevels = getNLevels(names); - - // initialise result arrays - Object[][] collectResults = new Object[nLevels][]; - int[] collectResultSize = new int[nLevels]; - for (int i = 0; i < collectResults.length; i++) { - collectResults[i] = new Object[INITIAL_SIZE]; - } - - // perform split - int factorLen = f.getLength(); - for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) { - int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based - // int vector - Object[] collect = collectResults[resultIndex]; - if (collect.length == collectResultSize[resultIndex]) { - collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); - collect = collectResults[resultIndex]; + @Specialization(limit = "4", guards = {"xAccess.supports(x)", "fAccess.supports(f)"}) + protected RList split(RAbstractVector x, RAbstractIntVector f, + @Cached("x.access()") VectorAccess xAccess, + @Cached("f.access()") VectorAccess fAccess) { + try (SequentialIterator xIter = xAccess.access(x); SequentialIterator fIter = fAccess.access(f)) { + RStringVector names = getLevelNode.execute(f); + int nLevels = getNLevels(names); + int[] collectResultSize = new int[nLevels]; + Object[] results = new Object[nLevels]; + + switch (xAccess.getType()) { + case Character: { + // Initialize result arrays + String[][] collectResults = new String[nLevels][INITIAL_SIZE]; + + // perform split + while (xAccess.next(xIter)) { + fAccess.nextWithWrap(fIter); + int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int + // vector + String[] collect = collectResults[resultIndex]; + if (collect.length == collectResultSize[resultIndex]) { + collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); + } + collect[collectResultSize[resultIndex]++] = xAccess.getString(xIter); + } + + RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize); + for (int i = 0; i < nLevels; i++) { + results[i] = RDataFactory.createStringVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(), + (resultNames != null) ? resultNames[i] : null); + } + break; + } + case Complex: { + // Initialize result arrays + double[][] collectResults = new double[nLevels][INITIAL_SIZE * 2]; + + // perform split + while (xAccess.next(xIter)) { + fAccess.nextWithWrap(fIter); + int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int + // vector + double[] collect = collectResults[resultIndex]; + if (collect.length == collectResultSize[resultIndex] * 2) { + collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); + } + collect[collectResultSize[resultIndex] * 2] = xAccess.getComplexR(xIter); + collect[collectResultSize[resultIndex] * 2 + 1] = xAccess.getComplexI(xIter); + collectResultSize[resultIndex]++; + } + + RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize); + for (int i = 0; i < nLevels; i++) { + results[i] = RDataFactory.createComplexVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i] * 2), x.isComplete(), + (resultNames != null) ? resultNames[i] : null); + } + break; + } + case Double: { + // Initialize result arrays + double[][] collectResults = new double[nLevels][INITIAL_SIZE]; + + // perform split + while (xAccess.next(xIter)) { + fAccess.nextWithWrap(fIter); + int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int + // vector + double[] collect = collectResults[resultIndex]; + if (collect.length == collectResultSize[resultIndex]) { + collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); + } + collect[collectResultSize[resultIndex]++] = xAccess.getDouble(xIter); + } + + RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize); + for (int i = 0; i < nLevels; i++) { + results[i] = RDataFactory.createDoubleVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(), + (resultNames != null) ? resultNames[i] : null); + } + break; + } + case Integer: { + // Initialize result arrays + int[][] collectResults = new int[nLevels][INITIAL_SIZE]; + + // perform split + while (xAccess.next(xIter)) { + fAccess.nextWithWrap(fIter); + int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int + // vector + int[] collect = collectResults[resultIndex]; + if (collect.length == collectResultSize[resultIndex]) { + collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); + } + collect[collectResultSize[resultIndex]++] = xAccess.getInt(xIter); + } + + RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize); + for (int i = 0; i < nLevels; i++) { + results[i] = RDataFactory.createIntVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(), + (resultNames != null) ? resultNames[i] : null); + } + break; + } + case List: { + // Initialize result arrays + Object[][] collectResults = new Object[nLevels][INITIAL_SIZE]; + + // perform split + while (xAccess.next(xIter)) { + fAccess.nextWithWrap(fIter); + int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int + // vector + Object[] collect = collectResults[resultIndex]; + if (collect.length == collectResultSize[resultIndex]) { + collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); + } + collect[collectResultSize[resultIndex]++] = xAccess.getListElement(xIter); + } + + RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize); + for (int i = 0; i < nLevels; i++) { + results[i] = RDataFactory.createList(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), + (resultNames != null) ? resultNames[i] : null); + } + break; + } + case Logical: { + // Initialize result arrays + byte[][] collectResults = new byte[nLevels][INITIAL_SIZE]; + + // perform split + while (xAccess.next(xIter)) { + fAccess.nextWithWrap(fIter); + int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int + // vector + byte[] collect = collectResults[resultIndex]; + if (collect.length == collectResultSize[resultIndex]) { + collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); + } + collect[collectResultSize[resultIndex]++] = xAccess.getLogical(xIter); + } + + RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize); + for (int i = 0; i < nLevels; i++) { + results[i] = RDataFactory.createLogicalVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(), + (resultNames != null) ? resultNames[i] : null); + } + break; + } + case Raw: { + // Initialize result arrays + byte[][] collectResults = new byte[nLevels][INITIAL_SIZE]; + + // perform split + while (xAccess.next(xIter)) { + fAccess.nextWithWrap(fIter); + int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int + // vector + byte[] collect = collectResults[resultIndex]; + if (collect.length == collectResultSize[resultIndex]) { + collectResults[resultIndex] = collect = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); + } + collect[collectResultSize[resultIndex]++] = xAccess.getRaw(xIter); + } + + RStringVector[] resultNames = getSplitNames.getNames(x, fAccess, fIter, nLevels, collectResultSize); + for (int i = 0; i < nLevels; i++) { + results[i] = RDataFactory.createRawVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), + (resultNames != null) ? resultNames[i] : null); + } + break; + } + default: + throw error(Message.UNIMPLEMENTED_TYPE_IN_FUNCTION, xAccess.getType().getName(), "split"); } - collect[collectResultSize[resultIndex]++] = x.getDataAt(i); - } - - Object[] results = new Object[nLevels]; - RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize); - for (int i = 0; i < nLevels; i++) { - results[i] = RDataFactory.createList(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), - (resultNames != null) ? resultNames[i] : null); - } - return RDataFactory.createList(results, names); - } - - @Specialization - protected RList split(RAbstractIntVector x, RAbstractIntVector f) { - Object fStore = factorAccess.getDataStore(f); - RStringVector names = getLevelNode.execute(f); - final int nLevels = getNLevels(names); - - // initialise result arrays - int[][] collectResults = new int[nLevels][]; - int[] collectResultSize = new int[nLevels]; - for (int i = 0; i < collectResults.length; i++) { - collectResults[i] = new int[INITIAL_SIZE]; - } - - // perform split - int factorLen = f.getLength(); - for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) { - int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based - // int vector - int[] collect = collectResults[resultIndex]; - if (collect.length == collectResultSize[resultIndex]) { - collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); - collect = collectResults[resultIndex]; - } - collect[collectResultSize[resultIndex]++] = x.getDataAt(i); - } - - Object[] results = new Object[nLevels]; - RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize); - for (int i = 0; i < nLevels; i++) { - results[i] = RDataFactory.createIntVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(), - (resultNames != null) ? resultNames[i] : null); - } - return RDataFactory.createList(results, names); - } - - @Specialization - protected RList split(RAbstractDoubleVector x, RAbstractIntVector f) { - Object fStore = factorAccess.getDataStore(f); - RStringVector names = getLevelNode.execute(f); - final int nLevels = getNLevels(names); - - // initialise result arrays - double[][] collectResults = new double[nLevels][]; - int[] collectResultSize = new int[nLevels]; - for (int i = 0; i < collectResults.length; i++) { - collectResults[i] = new double[INITIAL_SIZE]; - } - - // perform split - int factorLen = f.getLength(); - for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) { - int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based - // int vector - double[] collect = collectResults[resultIndex]; - if (collect.length == collectResultSize[resultIndex]) { - collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); - collect = collectResults[resultIndex]; - } - collect[collectResultSize[resultIndex]++] = x.getDataAt(i); - } - - Object[] results = new Object[nLevels]; - RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize); - for (int i = 0; i < nLevels; i++) { - results[i] = RDataFactory.createDoubleVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), RDataFactory.COMPLETE_VECTOR, - (resultNames != null) ? resultNames[i] : null); + return RDataFactory.createList(results, names); } - return RDataFactory.createList(results, names); } - @Specialization - protected RList split(RAbstractStringVector x, RAbstractIntVector f) { - Object fStore = factorAccess.getDataStore(f); - RStringVector names = getLevelNode.execute(f); - final int nLevels = getNLevels(names); - - // initialise result arrays - String[][] collectResults = new String[nLevels][]; - int[] collectResultSize = new int[nLevels]; - for (int i = 0; i < collectResults.length; i++) { - collectResults[i] = new String[INITIAL_SIZE]; - } - - // perform split - int factorLen = f.getLength(); - for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) { - int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based - // int vector - String[] collect = collectResults[resultIndex]; - if (collect.length == collectResultSize[resultIndex]) { - collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); - collect = collectResults[resultIndex]; - } - collect[collectResultSize[resultIndex]++] = x.getDataAt(i); - } - - Object[] results = new Object[nLevels]; - RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize); - for (int i = 0; i < nLevels; i++) { - results[i] = RDataFactory.createStringVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), RDataFactory.COMPLETE_VECTOR, - (resultNames != null) ? resultNames[i] : null); - } - return RDataFactory.createList(results, names); + @Specialization(replaces = "split") + protected RList splitGeneric(RAbstractVector x, RAbstractIntVector f) { + return split(x, f, x.slowPathAccess(), f.slowPathAccess()); } - @Specialization - protected RList split(RAbstractLogicalVector x, RAbstractIntVector f) { - Object fStore = factorAccess.getDataStore(f); - RStringVector names = getLevelNode.execute(f); - final int nLevels = getNLevels(names); - - // initialise result arrays - byte[][] collectResults = new byte[nLevels][]; - int[] collectResultSize = new int[nLevels]; - for (int i = 0; i < collectResults.length; i++) { - collectResults[i] = new byte[INITIAL_SIZE]; - } - - // perform split - int factorLen = f.getLength(); - for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) { - int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based - // int vector - byte[] collect = collectResults[resultIndex]; - if (collect.length == collectResultSize[resultIndex]) { - collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); - collect = collectResults[resultIndex]; + protected abstract static class GetSplitNames extends RBaseNode { + + private final ConditionProfile namesProfile = ConditionProfile.createBinaryProfile(); + @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); + + private RStringVector[] getNames(RAbstractVector x, VectorAccess fAccess, SequentialIterator fIter, int nLevels, int[] collectResultSize) { + RStringVector xNames = getNamesNode.getNames(x); + if (namesProfile.profile(xNames != null)) { + String[][] namesArr = new String[nLevels][]; + int[] resultNamesIdxs = new int[nLevels]; + for (int i = 0; i < nLevels; i++) { + namesArr[i] = new String[collectResultSize[i]]; + } + execute(fAccess, fIter, xNames, namesArr, resultNamesIdxs); + RStringVector[] resultNames = new RStringVector[nLevels]; + for (int i = 0; i < nLevels; i++) { + resultNames[i] = RDataFactory.createStringVector(namesArr[i], xNames.isComplete()); + } + return resultNames; } - collect[collectResultSize[resultIndex]++] = x.getDataAt(i); + return null; } - Object[] results = new Object[nLevels]; - RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize); - for (int i = 0; i < nLevels; i++) { - results[i] = RDataFactory.createLogicalVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), x.isComplete(), - (resultNames != null) ? resultNames[i] : null); - } - return RDataFactory.createList(results, names); - } - - @Specialization - protected RList split(RRawVector x, RAbstractIntVector f) { - Object fStore = factorAccess.getDataStore(f); - RStringVector names = getLevelNode.execute(f); - final int nLevels = getNLevels(names); - - // initialise result arrays - byte[][] collectResults = new byte[nLevels][]; - int[] collectResultSize = new int[nLevels]; - for (int i = 0; i < collectResults.length; i++) { - collectResults[i] = new byte[INITIAL_SIZE]; - } - - // perform split - int factorLen = f.getLength(); - for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) { - int resultIndex = factorAccess.getDataAt(f, fStore, fi) - 1; // a factor is a 1-based - // int vector - byte[] collect = collectResults[resultIndex]; - if (collect.length == collectResultSize[resultIndex]) { - collectResults[resultIndex] = Arrays.copyOf(collect, collect.length * SCALE_FACTOR); - collect = collectResults[resultIndex]; + protected abstract void execute(VectorAccess fAccess, SequentialIterator fIter, RStringVector names, String[][] namesArr, int[] resultNamesIdxs); + + @Specialization(guards = "namesAccess.supports(names)") + protected void fillNames(VectorAccess fAccess, SequentialIterator fIter, RStringVector names, String[][] namesArr, int[] resultNamesIdxs, + @Cached("names.access()") VectorAccess namesAccess) { + try (SequentialIterator namesIter = namesAccess.access(names)) { + while (namesAccess.next(namesIter)) { + fAccess.nextWithWrap(fIter); + int resultIndex = fAccess.getInt(fIter) - 1; // a factor is a 1-based int + // vector + namesArr[resultIndex][resultNamesIdxs[resultIndex]++] = namesAccess.getString(namesIter); + } } - collect[collectResultSize[resultIndex]++] = x.getRawDataAt(i); } - Object[] results = new Object[nLevels]; - RStringVector[] resultNames = getNames(x, f, fStore, nLevels, collectResultSize); - for (int i = 0; i < nLevels; i++) { - results[i] = RDataFactory.createRawVector(Arrays.copyOfRange(collectResults[i], 0, collectResultSize[i]), - (resultNames != null) ? resultNames[i] : null); - } - return RDataFactory.createList(results, names); - } - - private RStringVector[] getNames(RAbstractVector x, RAbstractIntVector factor, Object fStore, int nLevels, int[] collectResultSize) { - RStringVector xNames = getNamesNode.getNames(x); - if (namesProfile.profile(xNames != null)) { - String[][] namesArr = new String[nLevels][]; - int[] resultNamesIdxs = new int[nLevels]; - for (int i = 0; i < nLevels; i++) { - namesArr[i] = new String[collectResultSize[i]]; - } - int factorLen = factor.getLength(); - for (int i = 0, fi = 0; i < x.getLength(); ++i, fi = Utils.incMod(fi, factorLen)) { - int resultIndex = factorAccess.getDataAt(factor, fStore, fi) - 1; // a factor is a - // 1-based int - // vector - namesArr[resultIndex][resultNamesIdxs[resultIndex]++] = xNames.getDataAt(i); - } - RStringVector[] resultNames = new RStringVector[nLevels]; - for (int i = 0; i < nLevels; i++) { - resultNames[i] = RDataFactory.createStringVector(namesArr[i], xNames.isComplete()); - } - return resultNames; + @Specialization(replaces = "fillNames") + protected void fillNamesGeneric(VectorAccess fAccess, SequentialIterator fIter, RStringVector names, String[][] namesArr, int[] resultNamesIdxs) { + fillNames(fAccess, fIter, names, namesArr, resultNamesIdxs, names.slowPathAccess()); } - return null; } private static int getNLevels(RStringVector levels) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java index b61abc3dc009fa760ff99ca77b3bcb47ffc58f11..e48d76d60b510b783cc077266c62cd66f2114f8d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Transpose.java @@ -15,10 +15,6 @@ 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 java.util.function.BiFunction; -import java.util.function.Function; - -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; @@ -35,27 +31,18 @@ import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.function.opt.ReuseNonSharedNode; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; -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; -import com.oracle.truffle.r.runtime.data.RIntVector; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RVector; -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.RAbstractListVector; -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.SetDataAt; -import com.oracle.truffle.r.runtime.data.nodes.VectorReadAccess; +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.VectorReuse; import com.oracle.truffle.r.runtime.nodes.RBaseNode; @RBuiltin(name = "t.default", kind = INTERNAL, parameterNames = {"x"}, behavior = PURE) @@ -72,7 +59,7 @@ public abstract class Transpose extends RBuiltinNode.Arg1 { @Child private SetFixedAttributeNode putDimNames = SetFixedAttributeNode.createDimNames(); @Child private GetDimNamesAttributeNode getDimNamesNode = GetDimNamesAttributeNode.create(); @Child private GetNamesAttributeNode getAxisNamesNode = GetNamesAttributeNode.create(); - @Child private GetDimAttributeNode getDimNode; + @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create(); @Child private ReuseNonSharedNode reuseNonShared = ReuseNonSharedNode.create(); static { @@ -81,210 +68,157 @@ public abstract class Transpose extends RBuiltinNode.Arg1 { public abstract Object execute(RAbstractVector o); - @FunctionalInterface - private interface WriteArray<T extends RAbstractVector, A> { - void apply(A array, T vector, int i, int j); - } - - @FunctionalInterface - private interface Swap { - /** Swap element at (i, j) with element at (j, i). */ - void swap(int i, int j); + protected boolean isSquare(RAbstractVector vector) { + int[] dims = getDimNode.getDimensions(vector); + if (GetDimAttributeNode.isMatrix(dims)) { + assert dims.length >= 2; + return dims[0] == dims[1]; + } + return false; } - protected <T extends RAbstractVector, A> RVector<?> transposeInternal(T vector, Function<Integer, A> createArray, WriteArray<T, A> writeArray, BiFunction<A, Boolean, RVector<?>> createResult) { - int length = lengthProfile.profile(vector.getLength()); - int firstDim; - int secondDim; - assert vector.isMatrix(); - int[] dims = getDimensions(vector); - firstDim = dims[0]; - secondDim = dims[1]; - RBaseNode.reportWork(this, length); - - A array = createArray.apply(length); - int j = 0; - loopProfile.profileCounted(length); - for (int i = 0; loopProfile.inject(i < length); i++, j += firstDim) { - if (j > (length - 1)) { - j -= (length - 1); - } - writeArray.apply(array, vector, i, j); - } - RVector<?> r = createResult.apply(array, vector.isComplete()); - // copy attributes - copyRegAttributes.execute(vector, r); - // set new dimensions - int[] newDim = new int[]{secondDim, firstDim}; - putNewDimensions(vector, r, newDim); - return r; + protected boolean isMatrix(RAbstractVector vector) { + return GetDimAttributeNode.isMatrix(getDimNode.getDimensions(vector)); } - protected RVector<?> transposeSquareMatrixInPlace(RVector<?> vector, Object store, VectorReadAccess readAccess, SetDataAt setter, Swap swap) { + private void transposeSquareMatrixInPlace(RAbstractVector vector, RandomIterator iter, VectorAccess access) { int length = lengthProfile.profile(vector.getLength()); - assert vector.isMatrix(); - int[] dims = getDimensions(vector); + assert isMatrix(vector); + int[] dims = getDimNode.getDimensions(vector); assert dims.length == 2; assert dims[0] == dims[1]; int dim = dims[0]; RBaseNode.reportWork(this, length); + RType type = access.getType(); loopProfile.profileCounted(length); for (int i = 0; loopProfile.inject(i < dim); i++) { for (int j = 0; j < i; j++) { int swapi = i * dim + j; int swapj = j * dim + i; - if (swap != null) { - swap.swap(swapi, swapj); - } else { - Object tmp = readAccess.getDataAtAsObject(vector, store, swapi); - Object jVal = readAccess.getDataAtAsObject(vector, store, swapj); - setter.setDataAtAsObject(vector, store, swapi, jVal); - setter.setDataAtAsObject(vector, store, swapj, tmp); + switch (type) { + case Character: { + String tmp = access.getString(iter, swapi); + access.setString(iter, swapi, access.getString(iter, swapj)); + access.setString(iter, swapj, tmp); + break; + } + case Complex: { + double tmpReal = access.getComplexR(iter, swapi); + double tmpImaginary = access.getComplexI(iter, swapi); + access.setComplex(iter, swapi, access.getComplexR(iter, swapj), access.getComplexI(iter, swapj)); + access.setComplex(iter, swapj, tmpReal, tmpImaginary); + break; + } + case Double: { + double tmp = access.getDouble(iter, swapi); + access.setDouble(iter, swapi, access.getDouble(iter, swapj)); + access.setDouble(iter, swapj, tmp); + break; + } + case Integer: { + int tmp = access.getInt(iter, swapi); + access.setInt(iter, swapi, access.getInt(iter, swapj)); + access.setInt(iter, swapj, tmp); + break; + } + case List: { + Object tmp = access.getListElement(iter, swapi); + access.setListElement(iter, swapi, access.getListElement(iter, swapj)); + access.setListElement(iter, swapj, tmp); + break; + } + case Logical: { + byte tmp = access.getLogical(iter, swapi); + access.setLogical(iter, swapi, access.getLogical(iter, swapj)); + access.setLogical(iter, swapj, tmp); + break; + } + case Raw: { + byte tmp = access.getRaw(iter, swapi); + access.setRaw(iter, swapi, access.getRaw(iter, swapj)); + access.setRaw(iter, swapj, tmp); + break; + } + default: + throw RInternalError.shouldNotReachHere(); } } } // don't need to set new dimensions; it is a square matrix putNewDimNames(vector, vector); - return vector; } - private int[] getDimensions(RAbstractVector vector) { - assert vector.isMatrix(); - if (getDimNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getDimNode = insert(GetDimAttributeNode.create()); + @Specialization(guards = {"isSquare(x)", "!isRExpression(x)", "xReuse.supports(x)"}) + protected RAbstractVector transposeSquare(RAbstractVector x, + @Cached("createNonShared(x)") VectorReuse xReuse) { + RAbstractVector result = xReuse.getResult(x); + VectorAccess resultAccess = xReuse.access(result); + try (RandomIterator resultIter = resultAccess.randomAccess(result)) { + transposeSquareMatrixInPlace(result, resultIter, resultAccess); } - return getDimNode.getDimensions(vector); - } - - protected boolean isSquare(RAbstractVector vector) { - if (vector.isMatrix()) { - int[] dims = getDimensions(vector); - assert dims.length >= 2; - return dims[0] == dims[1]; + return result; + } + + @Specialization(replaces = "transposeSquare", guards = {"isSquare(x)", "!isRExpression(x)"}) + protected RAbstractVector transposeSquareGeneric(RAbstractVector x, + @Cached("createNonSharedGeneric()") VectorReuse xReuse) { + return transposeSquare(x, xReuse); + } + + @Specialization(guards = {"isMatrix(x)", "!isSquare(x)", "!isRExpression(x)", "xAccess.supports(x)"}) + protected RAbstractVector transpose(RAbstractVector x, + @Cached("create()") VectorFactory factory, + @Cached("x.access()") VectorAccess xAccess, + @Cached("createNew(xAccess.getType())") VectorAccess resultAccess) { + try (RandomIterator xIter = xAccess.randomAccess(x)) { + RAbstractVector result = factory.createVector(xAccess.getType(), xAccess.getLength(xIter), false); + try (RandomIterator resultIter = resultAccess.randomAccess(result)) { + int length = lengthProfile.profile(xAccess.getLength(xIter)); + assert isMatrix(x); + int[] dims = getDimNode.getDimensions(x); + int firstDim = dims[0]; + int secondDim = dims[1]; + RBaseNode.reportWork(this, length); + + int j = 0; + loopProfile.profileCounted(length); + for (int i = 0; loopProfile.inject(i < length); i++, j += firstDim) { + if (j > (length - 1)) { + j -= (length - 1); + } + resultAccess.setFromSameType(resultIter, i, xAccess, xIter, j); + } + // copy attributes + copyRegAttributes.execute(x, result); + // set new dimensions + putNewDimensions(x, result, new int[]{secondDim, firstDim}); + } + result.setComplete(x.isComplete()); + return result; } - return false; - } - - @Specialization(guards = "isSquare(x)") - protected RVector<?> transposeSquare(RAbstractIntVector x, - @Cached("create()") VectorReadAccess.Int readAccess, - @Cached("create()") SetDataAt.Int setter) { - RIntVector reused = (RIntVector) reuseNonShared.execute(x).materialize(); - Object reusedStore = readAccess.getDataStore(reused); - return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null); - } - - @Specialization(guards = "isSquare(x)") - protected RVector<?> transposeSquare(RAbstractLogicalVector x, - @Cached("create()") VectorReadAccess.Logical readAccess, - @Cached("create()") SetDataAt.Logical setter) { - RLogicalVector reused = (RLogicalVector) reuseNonShared.execute(x).materialize(); - Object reusedStore = readAccess.getDataStore(reused); - return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null); - } - - @Specialization(guards = "isSquare(x)") - protected RVector<?> transposeSquare(RAbstractDoubleVector x, - @Cached("create()") VectorReadAccess.Double readAccess, - @Cached("create()") SetDataAt.Double setter) { - RDoubleVector reused = (RDoubleVector) reuseNonShared.execute(x).materialize(); - Object reusedStore = readAccess.getDataStore(reused); - return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null); - } - - @Specialization(guards = "isSquare(x)") - protected RVector<?> transposeSquare(RAbstractComplexVector x, - @Cached("create()") VectorReadAccess.Complex readAccess, - @Cached("create()") SetDataAt.Complex setter) { - RComplexVector reused = (RComplexVector) reuseNonShared.execute(x).materialize(); - Object reusedStore = readAccess.getDataStore(reused); - return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null); - } - - @Specialization(guards = "isSquare(x)") - protected RVector<?> transposeSquare(RAbstractStringVector x, - @Cached("create()") VectorReadAccess.String readAccess, - @Cached("create()") SetDataAt.String setter) { - RStringVector reused = (RStringVector) reuseNonShared.execute(x).materialize(); - Object reusedStore = readAccess.getDataStore(reused); - return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null); - } - - @Specialization(guards = "isSquare(x)") - protected RVector<?> transposeSquare(RAbstractListVector x) { - RList reused = (RList) reuseNonShared.execute(x).materialize(); - Object[] store = reused.getDataWithoutCopying(); - return transposeSquareMatrixInPlace(reused, store, null, null, (i, j) -> { - Object tmp = store[i]; - store[i] = store[j]; - store[j] = tmp; - }); - } - - @Specialization(guards = "isSquare(x)") - protected RVector<?> transposeSquare(RAbstractRawVector x, - @Cached("create()") VectorReadAccess.Raw readAccess, - @Cached("create()") SetDataAt.Raw setter) { - RRawVector reused = (RRawVector) reuseNonShared.execute(x).materialize(); - Object reusedStore = readAccess.getDataStore(reused); - return transposeSquareMatrixInPlace(reused, reusedStore, readAccess, setter, null); - } - - @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"}) - protected RVector<?> transpose(RAbstractIntVector x) { - return transposeInternal(x, l -> new int[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createIntVector); - } - - @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"}) - protected RVector<?> transpose(RAbstractLogicalVector x) { - return transposeInternal(x, l -> new byte[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createLogicalVector); - } - - @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"}) - protected RVector<?> transpose(RAbstractDoubleVector x) { - return transposeInternal(x, l -> new double[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createDoubleVector); - } - - @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"}) - protected RVector<?> transpose(RAbstractComplexVector x) { - return transposeInternal(x, l -> new double[l * 2], (a, v, i, j) -> { - RComplex d = v.getDataAt(j); - a[i * 2] = d.getRealPart(); - a[i * 2 + 1] = d.getImaginaryPart(); - }, RDataFactory::createComplexVector); - } - - @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"}) - protected RVector<?> transpose(RAbstractStringVector x) { - return transposeInternal(x, l -> new String[l], (a, v, i, j) -> a[i] = v.getDataAt(j), RDataFactory::createStringVector); - } - - @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"}) - protected RVector<?> transpose(RAbstractListVector x) { - return transposeInternal(x, l -> new Object[l], (a, v, i, j) -> a[i] = v.getDataAt(j), (a, c) -> RDataFactory.createList(a)); } - @Specialization(guards = {"x.isMatrix()", "!isSquare(x)"}) - protected RVector<?> transpose(RAbstractRawVector x) { - return transposeInternal(x, l -> new byte[l], (a, v, i, j) -> a[i] = v.getRawDataAt(j), (a, c) -> RDataFactory.createRawVector(a)); + @Specialization(replaces = "transpose", guards = {"isMatrix(x)", "!isSquare(x)", "!isRExpression(x)"}) + protected RAbstractVector transposeGeneric(RAbstractVector x, + @Cached("create()") VectorFactory factory) { + return transpose(x, factory, x.slowPathAccess(), VectorAccess.createSlowPathNew(x.getRType())); } - @Specialization(guards = "!x.isMatrix()") - protected RVector<?> transpose(RAbstractVector x) { + @Specialization(guards = {"!isMatrix(x)", "!isRExpression(x)"}) + protected RVector<?> transposeNonMatrix(RAbstractVector x) { RVector<?> reused = reuseNonShared.execute(x); putNewDimensions(reused, reused, new int[]{1, x.getLength()}); return reused; } - private void putNewDimensions(RAbstractVector source, RVector<?> dest, int[] newDim) { + private void putNewDimensions(RAbstractVector source, RAbstractVector dest, int[] newDim) { putDimensions.execute(initAttributes.execute(dest), RDataFactory.createIntVector(newDim, RDataFactory.COMPLETE_VECTOR)); putNewDimNames(source, dest); } - private void putNewDimNames(RAbstractVector source, RVector<?> dest) { + private void putNewDimNames(RAbstractVector source, RAbstractVector dest) { // set new dim names RList dimNames = getDimNamesNode.getDimNames(source); if (dimNames != null) { @@ -292,8 +226,7 @@ public abstract class Transpose extends RBuiltinNode.Arg1 { assert dimNames.getLength() == 2; RStringVector axisNames = getAxisNamesNode.getNames(dimNames); RStringVector transAxisNames = axisNames == null ? null : RDataFactory.createStringVector(new String[]{axisNames.getDataAt(1), axisNames.getDataAt(0)}, true); - RList newDimNames = RDataFactory.createList(new Object[]{dimNames.getDataAt(1), - dimNames.getDataAt(0)}, transAxisNames); + RList newDimNames = RDataFactory.createList(new Object[]{dimNames.getDataAt(1), dimNames.getDataAt(0)}, transAxisNames); putDimNames.execute(dest.getAttributes(), newDimNames); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java index 5efb1486a32c28a3cedb2e7530ad7eefd352298b..b53035ae7c895902257bc7f7c7ac685858b4ab35 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/UpdateAttributes.java @@ -62,9 +62,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector; @RBuiltin(name = "attributes<-", kind = PRIMITIVE, parameterNames = {"obj", "value"}, behavior = PURE) public abstract class UpdateAttributes extends RBuiltinNode.Arg2 { - private final ConditionProfile numAttributesProfile = ConditionProfile.createBinaryProfile(); - @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); + @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); @Child private UpdateNames updateNames; @Child private UpdateDimNames updateDimNames; @Child private CastIntegerNode castInteger; @@ -128,16 +127,17 @@ public abstract class UpdateAttributes extends RBuiltinNode.Arg2 { @Specialization protected RAbstractContainer updateAttributes(RAbstractContainer container, RList list, - @Cached("create()") GetNonSharedNode nonShared) { - Object listNamesObject = getNamesNode.getNames(list); - if (listNamesObject == null || listNamesObject == RNull.instance) { - throw error(RError.Message.ATTRIBUTES_NAMED); - } - RStringVector listNames = (RStringVector) listNamesObject; + @Cached("create()") GetNonSharedNode nonShared, + @Cached("createBinaryProfile()") ConditionProfile emptyListProfile) { RAbstractContainer result = ((RAbstractContainer) nonShared.execute(container)).materialize(); - if (numAttributesProfile.profile(list.getLength() == 0)) { + if (emptyListProfile.profile(list.getLength() == 0)) { result.resetAllAttributes(true); } else { + Object listNamesObject = getNamesNode.getNames(list); + if (listNamesObject == null || listNamesObject == RNull.instance) { + throw error(RError.Message.ATTRIBUTES_NAMED); + } + RStringVector listNames = (RStringVector) listNamesObject; result.resetAllAttributes(false); // error checking is a little weird - seems easier to separate it than weave it into the // update loop diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java index 48f97b147f36682ec368ac5e61fe3914693c4765..9d9aeef9d87eeb09cd5963d5bab80650d8c80fd4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/fastpaths/MatrixFastPath.java @@ -32,6 +32,7 @@ import com.oracle.truffle.r.nodes.builtin.base.MatrixNodeGen; import com.oracle.truffle.r.nodes.unary.CastIntegerNode; import com.oracle.truffle.r.nodes.unary.FirstIntNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; @@ -64,6 +65,9 @@ public abstract class MatrixFastPath extends RFastPathNode { int row = rowMissing ? 1 : firstRow.executeInt(castRow.doCast(nrow)); int col = colMissing ? 1 : firstCol.executeInt(castCol.doCast(ncol)); Object dim = dimMissingProfile.profile(dimnames == RMissing.instance) ? RNull.instance : dimnames; + if (row == RRuntime.INT_NA || col == RRuntime.INT_NA) { + return null; + } return matrix.execute(classProfile.profile(data), row, col, false, dim, rowMissing, colMissing); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java index fa7bd093468a50b2f7af32a0ba00d1f728d75522..97bdda9d9a8aa0ef9ce10ea25e39e47dfed0f6b1 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/CallAndExternalFunctions.java @@ -324,43 +324,43 @@ public class CallAndExternalFunctions { case "qnorm": return StatsFunctionsNodes.Function3_2Node.create(new Qnorm()); case "rnorm": - return RandFunction2Node.createDouble(new Rnorm()); + return RandFunction2Node.createDouble(Rnorm::new); case "runif": - return RandFunction2Node.createDouble(new Runif()); + return RandFunction2Node.createDouble(Runif::new); case "rbeta": - return RandFunction2Node.createDouble(new RBeta()); + return RandFunction2Node.createDouble(RBeta::new); case "rgamma": - return RandFunction2Node.createDouble(new RGamma()); + return RandFunction2Node.createDouble(RGamma::new); case "rcauchy": - return RandFunction2Node.createDouble(new RCauchy()); + return RandFunction2Node.createDouble(RCauchy::new); case "rf": - return RandFunction2Node.createDouble(new Rf()); + return RandFunction2Node.createDouble(Rf::new); case "rlogis": - return RandFunction2Node.createDouble(new RLogis()); + return RandFunction2Node.createDouble(RLogis::new); case "rweibull": - return RandFunction2Node.createDouble(new RWeibull()); + return RandFunction2Node.createDouble(RWeibull::new); case "rnchisq": - return RandFunction2Node.createDouble(new RNchisq()); + return RandFunction2Node.createDouble(RNchisq::new); case "rnbinom_mu": - return RandFunction2Node.createDouble(new RNBinomMu()); + return RandFunction2Node.createDouble(RNBinomMu::new); case "rwilcox": - return RandFunction2Node.createInt(new RWilcox()); + return RandFunction2Node.createInt(RWilcox::new); case "rchisq": - return RandFunction1Node.createDouble(new RChisq()); + return RandFunction1Node.createDouble(RChisq::new); case "rexp": - return RandFunction1Node.createDouble(new RExp()); + return RandFunction1Node.createDouble(RExp::new); case "rgeom": - return RandFunction1Node.createInt(new RGeom()); + return RandFunction1Node.createInt(RGeom::new); case "rpois": - return RandFunction1Node.createInt(new RPois()); + return RandFunction1Node.createInt(RPois::new); case "rnbinom": - return RandFunction2Node.createInt(new RNBinomFunc()); + return RandFunction2Node.createInt(RNBinomFunc::new); case "rt": - return RandFunction1Node.createDouble(new Rt()); + return RandFunction1Node.createDouble(Rt::new); case "rsignrank": - return RandFunction1Node.createInt(new RSignrank()); + return RandFunction1Node.createInt(RSignrank::new); case "rhyper": - return RandFunction3Node.createInt(new RHyper()); + return RandFunction3Node.createInt(RHyper::new); case "phyper": return StatsFunctionsNodes.Function4_2Node.create(new PHyper()); case "dhyper": @@ -400,7 +400,7 @@ public class CallAndExternalFunctions { case "dweibull": return StatsFunctionsNodes.Function3_1Node.create(new DWeibull()); case "rbinom": - return RandFunction2Node.createInt(new Rbinom()); + return RandFunction2Node.createInt(Rbinom::new); case "pbinom": return StatsFunctionsNodes.Function3_2Node.create(new Pbinom()); case "pbeta": @@ -458,7 +458,7 @@ public class CallAndExternalFunctions { case "dt": return StatsFunctionsNodes.Function2_1Node.create(new Dt()); case "rlnorm": - return RandFunction2Node.createDouble(new LogNormal.RLNorm()); + return RandFunction2Node.createDouble(LogNormal.RLNorm::new); case "dlnorm": return StatsFunctionsNodes.Function3_1Node.create(new DLNorm()); case "qlnorm": diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AnyVectorToStringVectorWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AnyVectorToStringVectorWriter.java index 5282e1d86e05f9d9fda1a0aec8f1c9a7bba188e0..c3c58869de499c385be2b8630a20ac6d3407cec4 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AnyVectorToStringVectorWriter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AnyVectorToStringVectorWriter.java @@ -71,14 +71,14 @@ public class AnyVectorToStringVectorWriter extends Writer implements PrettyWrite } @Override - public void beginElement(@SuppressWarnings("hiding") RAbstractVector vector, int index, FormatMetrics fm) { + public void beginElement(int index, FormatMetrics fm) { if (levelCounter == 1) { sb = new StringBuilder(); } } @Override - public void endElement(@SuppressWarnings("hiding") RAbstractVector vector, int index, FormatMetrics fm) { + public void endElement(int index, FormatMetrics fm) { if (levelCounter == 1) { String s = sb.toString().trim(); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java index 9acd7e244cc288467929467e5bbe82e73deb2c77..99957bfd751f46e4ab8d04a00db0119cc4f86153 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ComplexVectorPrinter.java @@ -23,6 +23,8 @@ import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorPrinter.Scien import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; //Transcribed from GnuR, src/main/printutils.c @@ -52,13 +54,13 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe @Override protected FormatMetrics formatVector(int offs, int len) { - return formatComplexVector(vector, offs, len, 0, printCtx.parameters()); + return formatComplexVector(iterator, access, offs, len, 0, printCtx.parameters()); } @Override protected void printElement(int i, FormatMetrics fm) throws IOException { ComplexVectorMetrics cfm = (ComplexVectorMetrics) fm; - String v = encodeComplex(vector.getDataAt(i), cfm, '.', printCtx.parameters()); + String v = encodeComplex(access.getComplex(iterator, i), cfm, '.', printCtx.parameters()); out.print(v); } @@ -74,69 +76,47 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe } @TruffleBoundary - static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, PrintParameters pp) { - return formatComplexVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth()); + static ComplexVectorMetrics formatComplexVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, PrintParameters pp) { + return formatComplexVector(iter, access, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth()); } @TruffleBoundary - static ComplexVectorMetrics formatComplexVector(RAbstractComplexVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) { - - int wr; - int dr; - int er; - int wi; - int di; - int ei; + static ComplexVectorMetrics formatComplexVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) { /* format.info() or x[1..l] for both Re & Im */ - int left; - int right; - int sleft; int rt; int mnl; int mxl; int mxsl; int mxns; - int wF; - int iwF; int irt; int imnl; int imxl; int imxsl; int imxns; - int neg; - boolean naflag; - boolean rnanflag; - boolean rposinf; - boolean rneginf; - boolean inanflag; - boolean iposinf; - RComplex tmp; boolean allReZero = true; boolean allImZero = true; - - naflag = false; - rnanflag = false; - rposinf = false; - rneginf = false; - inanflag = false; - iposinf = false; - neg = 0; - + boolean naflag = false; + boolean rnanflag = false; + boolean rposinf = false; + boolean rneginf = false; + boolean inanflag = false; + boolean iposinf = false; + + int neg = 0; rt = mxl = mxsl = mxns = RRuntime.INT_MIN_VALUE; irt = imxl = imxsl = imxns = RRuntime.INT_MIN_VALUE; imnl = mnl = RRuntime.INT_MAX_VALUE; for (int i = 0; i < n; i++) { /* Now round */ - RComplex xi = x.getDataAt(offs + i); + RComplex xi = access.getComplex(iter, offs + i); if (RRuntime.isNA(xi.getRealPart()) || RRuntime.isNA(xi.getImaginaryPart())) { naflag = true; } else { /* real part */ - tmp = zprecr(xi, digits); - + RComplex tmp = zprecr(xi, digits); if (!RRuntime.isFinite(tmp.getRealPart())) { if (RRuntime.isNAorNaN(tmp.getRealPart())) { rnanflag = true; @@ -151,12 +131,12 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe } ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getRealPart(), digits); - left = sd.kpower + 1; + int left = sd.kpower + 1; if (sd.roundingwidens) { left--; } - sleft = sd.sgn + ((left <= 0) ? 1 : left); /* >= 1 */ - right = sd.nsig - left; /* #{digits} right of '.' ( > 0 often) */ + int sleft = sd.sgn + ((left <= 0) ? 1 : left); /* >= 1 */ + int right = sd.nsig - left; /* #{digits} right of '.' ( > 0 often) */ if (sd.sgn != 0) { neg = 1; /* if any < 0, need extra space for sign */ } @@ -194,12 +174,12 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe } ScientificDouble sd = DoubleVectorPrinter.scientific(tmp.getImaginaryPart(), digits); - left = sd.kpower + 1; + int left = sd.kpower + 1; if (sd.roundingwidens) { left--; } - sleft = (left <= 0) ? 1 : left; - right = sd.nsig - left; + int sleft = (left <= 0) ? 1 : left; + int right = sd.nsig - left; if (right > irt) { irt = right; @@ -229,6 +209,11 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe if (digits == 0) { rt = 0; } + int wr; + int dr; + int er; + int wi; + int wF; if (mxl != RRuntime.INT_MIN_VALUE) { if (mxl < 0) { mxsl = 1 + neg; @@ -253,6 +238,9 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe if (digits == 0) { irt = 0; } + int di; + int ei; + int iwF; if (imxl != RRuntime.INT_MIN_VALUE) { if (imxl < 0) { imxsl = 1; @@ -400,8 +388,11 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe @TruffleBoundary public static String encodeComplex(RComplex x, int digits, int sciPen, String naString) { - ComplexVectorMetrics cvm = formatComplexVector(x, 0, 1, 0, digits, sciPen, naString.length()); - return encodeComplex(x, cvm, '.', digits, naString); + VectorAccess access = x.slowPathAccess(); + try (RandomIterator iter = access.randomAccess(x)) { + ComplexVectorMetrics cvm = formatComplexVector(iter, access, 0, 1, 0, digits, sciPen, naString.length()); + return encodeComplex(x, cvm, '.', digits, naString); + } } @TruffleBoundary @@ -465,13 +456,19 @@ public final class ComplexVectorPrinter extends VectorPrinter<RAbstractComplexVe } public static String[] format(RAbstractComplexVector value, boolean trim, int nsmall, int width, char decimalMark, PrintParameters pp) { - ComplexVectorMetrics dfm = formatComplexVector(value, 0, value.getLength(), nsmall, pp); - ComplexVectorMetrics adjusted = new ComplexVectorMetrics(Math.max(trim ? 1 : dfm.wr, width), dfm.dr, dfm.er, Math.max(trim ? 1 : dfm.wi, width), dfm.di, dfm.ei); - - String[] result = new String[value.getLength()]; - for (int i = 0; i < value.getLength(); i++) { - result[i] = encodeComplex(value.getDataAt(i), adjusted, decimalMark, pp); + VectorAccess access = value.slowPathAccess(); + try (RandomIterator iter = access.randomAccess(value)) { + int length = access.getLength(iter); + ComplexVectorMetrics dfm = formatComplexVector(iter, access, 0, length, nsmall, pp); + int wr = Math.max(trim ? 1 : dfm.wr, width); + int wi = Math.max(trim ? 1 : dfm.wi, width); + ComplexVectorMetrics adjusted = new ComplexVectorMetrics(wr, dfm.dr, dfm.er, wi, dfm.di, dfm.ei); + + String[] result = new String[length]; + for (int i = 0; i < length; i++) { + result[i] = encodeComplex(access.getComplex(iter, i), adjusted, decimalMark, pp); + } + return result; } - return result; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java index 1c3df1c59f40dc33de4b909f935aa54be4febb28..afec29e85a7f87ca11f4ff92b22ba11dae5d90c5 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/DoubleVectorPrinter.java @@ -15,8 +15,10 @@ import java.io.IOException; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RDouble; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; //Transcribed from GnuR, src/main/format.c @@ -41,13 +43,13 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect @Override protected DoubleVectorMetrics formatVector(int offs, int len) { - return formatDoubleVector(vector, offs, len, 0, printCtx.parameters()); + return formatDoubleVector(iterator, access, offs, len, 0, printCtx.parameters()); } @Override protected void printElement(int i, FormatMetrics fm) throws IOException { DoubleVectorMetrics dfm = (DoubleVectorMetrics) fm; - String v = encodeReal(vector.getDataAt(i), dfm.maxWidth, dfm.d, dfm.e, '.', printCtx.parameters()); + String v = encodeReal(access.getDouble(iterator, i), dfm.maxWidth, dfm.d, dfm.e, '.', printCtx.parameters()); out.print(v); } @@ -68,12 +70,12 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect } @TruffleBoundary - static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, PrintParameters pp) { - return formatDoubleVector(x, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth()); + static DoubleVectorMetrics formatDoubleVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, PrintParameters pp) { + return formatDoubleVector(iter, access, offs, n, nsmall, pp.getDigits(), pp.getScipen(), pp.getNaWidth()); } @TruffleBoundary - public static DoubleVectorMetrics formatDoubleVector(RAbstractDoubleVector x, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) { + public static DoubleVectorMetrics formatDoubleVector(RandomIterator iter, VectorAccess access, int offs, int n, int nsmall, int digits, int sciPen, int naWidth) { int left; int right; int sleft; @@ -107,7 +109,7 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect mnl = RRuntime.INT_MAX_VALUE; for (int i = 0; i < n; i++) { - double xi = x.getDataAt(i + offs); + double xi = access.getDouble(iter, offs + i); if (!RRuntime.isFinite(xi)) { if (RRuntime.isNA(xi)) { naflag = true; @@ -368,8 +370,12 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect @TruffleBoundary public static String encodeReal(double x, int digits, char cdec, int sciPen, String naString) { - DoubleVectorMetrics dm = formatDoubleVector(RDataFactory.createDoubleVectorFromScalar(x), 0, 1, 0, digits, sciPen, naString.length()); - return encodeReal(x, dm.maxWidth, dm.d, dm.e, cdec, naString); + RDouble value = RDouble.valueOf(x); + VectorAccess access = value.slowPathAccess(); + try (RandomIterator iter = access.randomAccess(value)) { + DoubleVectorMetrics dm = formatDoubleVector(iter, access, 0, 1, 0, digits, sciPen, naString.length()); + return encodeReal(x, dm.maxWidth, dm.d, dm.e, cdec, naString); + } } @TruffleBoundary @@ -563,13 +569,17 @@ public final class DoubleVectorPrinter extends VectorPrinter<RAbstractDoubleVect } public static String[] format(RAbstractDoubleVector value, boolean trim, int nsmall, int width, char decimalMark, PrintParameters pp) { - DoubleVectorMetrics dfm = formatDoubleVector(value, 0, value.getLength(), nsmall, pp); - int w = Math.max(trim ? 1 : dfm.maxWidth, width); - - String[] result = new String[value.getLength()]; - for (int i = 0; i < value.getLength(); i++) { - result[i] = encodeReal(value.getDataAt(i), w, dfm.d, dfm.e, decimalMark, pp); + VectorAccess access = value.slowPathAccess(); + try (RandomIterator iter = access.randomAccess(value)) { + int length = access.getLength(iter); + DoubleVectorMetrics dfm = formatDoubleVector(iter, access, 0, length, nsmall, pp); + int w = Math.max(trim ? 1 : dfm.maxWidth, width); + + String[] result = new String[length]; + for (int i = 0; i < length; i++) { + result[i] = encodeReal(access.getDouble(iter, i), w, dfm.d, dfm.e, decimalMark, pp); + } + return result; } - return result; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java index f9d0ea7c4f89cb0cf9b1470a644d0615fee0eed6..6c7d6c4ae77dc7f4a932c91cec375c664c1083a8 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/IntegerVectorPrinter.java @@ -17,6 +17,8 @@ import java.io.IOException; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; //Transcribed from GnuR, src/main/printutils.c, src/main/format.c @@ -46,12 +48,12 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector @Override protected FormatMetrics formatVector(int offs, int len) { - return new FormatMetrics(formatIntVectorInternal(vector, offs, len, printCtx.parameters().getNaWidth())); + return new FormatMetrics(formatIntVectorInternal(iterator, access, offs, len, printCtx.parameters().getNaWidth())); } @Override protected void printElement(int i, FormatMetrics fm) throws IOException { - String v = encodeInteger(vector.getDataAt(i), fm.maxWidth, printCtx.parameters()); + String v = encodeInteger(access.getInt(iterator, i), fm.maxWidth, printCtx.parameters()); out.print(v); } @@ -66,7 +68,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector } } - static int formatIntVectorInternal(RAbstractIntVector x, int offs, int n, int naWidth) { + static int formatIntVectorInternal(RandomIterator iter, VectorAccess access, int offs, int n, int naWidth) { int xmin = RRuntime.INT_MAX_VALUE; int xmax = RRuntime.INT_MIN_VALUE; boolean naflag = false; @@ -74,7 +76,7 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector int fieldwidth; for (int i = 0; i < n; i++) { - int xi = x.getDataAt(offs + i); + int xi = access.getInt(iter, offs + i); if (xi == RRuntime.INT_NA) { naflag = true; } else { @@ -164,18 +166,22 @@ public final class IntegerVectorPrinter extends VectorPrinter<RAbstractIntVector } public static String[] format(RAbstractIntVector value, boolean trim, int width, PrintParameters pp) { - int w; - if (trim) { - w = 1; - } else { - w = formatIntVectorInternal(value, 0, value.getLength(), pp.getNaWidth()); - } - w = Math.max(w, width); + VectorAccess access = value.slowPathAccess(); + try (RandomIterator iter = access.randomAccess(value)) { + int w; + int length = access.getLength(iter); + if (trim) { + w = 1; + } else { + w = formatIntVectorInternal(iter, access, 0, length, pp.getNaWidth()); + } + w = Math.max(w, width); - String[] result = new String[value.getLength()]; - for (int i = 0; i < value.getLength(); i++) { - result[i] = encodeInteger(value.getDataAt(i), w, pp); + String[] result = new String[length]; + for (int i = 0; i < length; i++) { + result[i] = encodeInteger(access.getInt(iter, i), w, pp); + } + return result; } - return result; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java index 7c84d1caf7a79c2145c6ad528bd222ee4e6ed597..65694c0578f9cc5c94f3c3b15bddb268ab7e8056 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java @@ -24,7 +24,6 @@ import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RAttributable; -import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RNull; @@ -36,6 +35,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; 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.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; //Transcribed from GnuR, src/main/print.c @@ -77,8 +78,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> { } else if (tmp instanceof RAbstractLogicalVector) { RAbstractLogicalVector lv = (RAbstractLogicalVector) tmp; if (lv.getLength() == 1) { - int width = LogicalVectorPrinter.formatLogicalVectorInternal(lv, 0, 1, pp.getNaWidth()); - pbuf = LogicalVectorPrinter.encodeLogical(lv.getDataAt(0), width, pp); + pbuf = LogicalVectorPrinter.format(lv, false, 0, pp)[0]; } else { pbuf = "Logical," + lv.getLength(); } @@ -89,8 +89,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> { pbuf = "factor," + iv.getLength(); } else { if (iv.getLength() == 1) { - int width = IntegerVectorPrinter.formatIntVectorInternal(iv, 0, 1, pp.getNaWidth()); - pbuf = IntegerVectorPrinter.encodeInteger(iv.getDataAt(0), width, pp); + pbuf = IntegerVectorPrinter.format(iv, false, 0, pp)[0]; } else { pbuf = "Integer," + iv.getLength(); } @@ -98,31 +97,26 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> { } else if (tmp instanceof RAbstractDoubleVector) { RAbstractDoubleVector dv = (RAbstractDoubleVector) tmp; if (dv.getLength() == 1) { - DoubleVectorMetrics fm = DoubleVectorPrinter.formatDoubleVector(dv, 0, 1, 0, pp); - pbuf = DoubleVectorPrinter.encodeReal(dv.getDataAt(0), fm, pp); + pbuf = DoubleVectorPrinter.format(dv, false, 0, 0, '.', pp)[0]; } else { pbuf = "Numeric," + dv.getLength(); } } else if (tmp instanceof RAbstractComplexVector) { RAbstractComplexVector cv = (RAbstractComplexVector) tmp; if (cv.getLength() == 1) { - RComplex x = cv.getDataAt(0); - if (RRuntime.isNA(x.getRealPart()) || RRuntime.isNA(x.getImaginaryPart())) { - /* formatReal(NA) --> w=R_print.na_width, d=0, e=0 */ - pbuf = DoubleVectorPrinter.encodeReal(RRuntime.DOUBLE_NA, pp.getNaWidth(), 0, 0, '.', pp); - } else { - ComplexVectorMetrics cvm = ComplexVectorPrinter.formatComplexVector(x, 0, 1, 0, pp); - pbuf = ComplexVectorPrinter.encodeComplex(x, cvm, '.', pp); - } + pbuf = ComplexVectorPrinter.format(cv, false, 0, 0, '.', pp)[0]; } else { pbuf = "Complex," + cv.getLength(); } } else if (tmp instanceof RAbstractStringVector) { RAbstractStringVector sv = (RAbstractStringVector) tmp; if (sv.getLength() == 1) { - String ctmp = RRuntime.escapeString(sv.getDataAt(0), true, true); - int len = ctmp.length(); - if (len < 100) { + String ctmp; + VectorAccess access = sv.slowPathAccess(); + try (RandomIterator iter = access.randomAccess(sv)) { + ctmp = RRuntime.escapeString(access.getString(iter, 0), true, true); + } + if (ctmp.length() < 100) { pbuf = ctmp; } else { pbuf = Utils.trimSize(101, ctmp) + "\" [truncated]"; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java index 3421a15d5b01f989d577a8e5b274bea67a117002..7bb3d8274d49d4b4eebab8c3471a899445392726 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/LogicalVectorPrinter.java @@ -15,6 +15,8 @@ import java.io.IOException; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; //Transcribed from GnuR, src/main/printutils.c, src/main/format.c @@ -44,12 +46,12 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe @Override protected FormatMetrics formatVector(int offs, int len) { - return new FormatMetrics(formatLogicalVectorInternal(vector, offs, len, printCtx.parameters().getNaWidth())); + return new FormatMetrics(formatLogicalVectorInternal(iterator, access, offs, len, printCtx.parameters().getNaWidth())); } @Override protected void printElement(int i, FormatMetrics fm) throws IOException { - out.print(encodeLogical(vector.getDataAt(i), fm.maxWidth, printCtx.parameters())); + out.print(encodeLogical(access.getLogical(iterator, i), fm.maxWidth, printCtx.parameters())); } @Override @@ -63,10 +65,10 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe } } - static int formatLogicalVectorInternal(RAbstractLogicalVector x, int offs, int n, int naWidth) { + static int formatLogicalVectorInternal(RandomIterator iter, VectorAccess access, int offs, int n, int naWidth) { int fieldwidth = 1; for (int i = 0; i < n; i++) { - byte xi = x.getDataAt(offs + i); + byte xi = access.getLogical(iter, offs + i); if (xi == RRuntime.LOGICAL_NA) { if (fieldwidth < naWidth) { fieldwidth = naWidth; @@ -105,18 +107,22 @@ public final class LogicalVectorPrinter extends VectorPrinter<RAbstractLogicalVe } public static String[] format(RAbstractLogicalVector value, boolean trim, int width, PrintParameters pp) { - int w; - if (trim) { - w = 1; - } else { - w = formatLogicalVectorInternal(value, 0, value.getLength(), pp.getNaWidth()); - } - w = Math.max(w, width); + VectorAccess access = value.slowPathAccess(); + try (RandomIterator iter = access.randomAccess(value)) { + int length = access.getLength(iter); + int w; + if (trim) { + w = 1; + } else { + w = formatLogicalVectorInternal(iter, access, 0, length, pp.getNaWidth()); + } + w = Math.max(w, width); - String[] result = new String[value.getLength()]; - for (int i = 0; i < value.getLength(); i++) { - result[i] = encodeLogical(value.getDataAt(i), w, pp); + String[] result = new String[value.getLength()]; + for (int i = 0; i < length; i++) { + result[i] = encodeLogical(access.getLogical(iter, i), w, pp); + } + return result; } - return result; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyPrintWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyPrintWriter.java index 675bb97080f397e81113ed17aa37d1a63bad2182..138cbe4e58af0de7b3ab12f7b71c657e752da9e6 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyPrintWriter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyPrintWriter.java @@ -26,7 +26,6 @@ import java.io.PrintWriter; import java.io.Writer; import com.oracle.truffle.r.runtime.data.RAttributeStorage; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public class PrettyPrintWriter extends PrintWriter implements PrettyWriter { @@ -81,16 +80,16 @@ public class PrettyPrintWriter extends PrintWriter implements PrettyWriter { } @Override - public void beginElement(RAbstractVector vector, int index, FormatMetrics fm) { + public void beginElement(int index, FormatMetrics fm) { if (out instanceof PrettyWriter) { - ((PrettyWriter) out).beginElement(vector, index, fm); + ((PrettyWriter) out).beginElement(index, fm); } } @Override - public void endElement(RAbstractVector vector, int index, FormatMetrics fm) { + public void endElement(int index, FormatMetrics fm) { if (out instanceof PrettyWriter) { - ((PrettyWriter) out).endElement(vector, index, fm); + ((PrettyWriter) out).endElement(index, fm); } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyWriter.java index 9813e5cc9f439bee7ebc325a254a6a202dc9568e..b54c046686781bb656aa878817e2d9ed1efb2ff5 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyWriter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/PrettyWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,6 @@ package com.oracle.truffle.r.nodes.builtin.base.printer; import com.oracle.truffle.r.runtime.data.RAttributeStorage; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public interface PrettyWriter { @@ -39,9 +38,9 @@ public interface PrettyWriter { void endAttributes(RAttributeStorage value); - void beginElement(RAbstractVector vector, int index, FormatMetrics fm); + void beginElement(int index, FormatMetrics fm); - void endElement(RAbstractVector vector, int index, FormatMetrics fm); + void endElement(int index, FormatMetrics fm); Object getPrintReport(); } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RawVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RawVectorPrinter.java index bf648a7aa9f0280a5bbfa9ab0e4b0981ed74ea3d..f3ffdebdd96170f6dcf74d4e6507b02f4e850a41 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RawVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/RawVectorPrinter.java @@ -60,7 +60,7 @@ final class RawVectorPrinter extends VectorPrinter<RAbstractRawVector> { @Override @TruffleBoundary protected void printElement(int i, FormatMetrics fm) throws IOException { - String rs = RRuntime.rawToHexString(vector.getRawDataAt(i)); + String rs = RRuntime.rawToHexString(access.getRaw(iterator, i)); if (fm.maxWidth > 2) { StringBuilder str = new StringBuilder(fm.maxWidth); for (int j = 2; j < fm.maxWidth; j++) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrettyWriter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrettyWriter.java index de109409424251285af7b61c24615bf440702913..0e188fffc786d79c7f77ef0240e3799293aeaa02 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrettyWriter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringPrettyWriter.java @@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.builtin.base.printer; import java.io.StringWriter; import com.oracle.truffle.r.runtime.data.RAttributeStorage; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public class StringPrettyWriter extends StringWriter implements PrettyWriter { @@ -54,11 +53,11 @@ public class StringPrettyWriter extends StringWriter implements PrettyWriter { } @Override - public void beginElement(RAbstractVector vector, int index, FormatMetrics fm) { + public void beginElement(int index, FormatMetrics fm) { } @Override - public void endElement(RAbstractVector vector, int index, FormatMetrics fm) { + public void endElement(int index, FormatMetrics fm) { } @Override diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java index 5ba2ea9ebc1e0f52b2601b313cda108089ada5a4..13937fca383ca7404f733dde9edde436038b5e35 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/StringVectorPrinter.java @@ -18,6 +18,8 @@ import java.util.Arrays; import com.oracle.truffle.r.runtime.RRuntime; 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; //Transcribed from GnuR, src/main/format.c @@ -42,19 +44,19 @@ final class StringVectorPrinter extends VectorPrinter<RAbstractStringVector> { @Override protected FormatMetrics formatVector(int offs, int len) { - int w = formatString(vector, offs, len, quote, printCtx.parameters()); + int w = formatString(iterator, access, offs, len, quote, printCtx.parameters()); return new FormatMetrics(w); } @Override protected void printElement(int i, FormatMetrics fm) throws IOException { - String s = vector.getDataAt(i); + String s = access.getString(iterator, i); StringVectorPrinter.printString(s, fm.maxWidth, printCtx); } @Override protected void printCell(int i, FormatMetrics fm) throws IOException { - String s = vector.getDataAt(i); + String s = access.getString(iterator, i); String outS = StringVectorPrinter.encode(s, fm.maxWidth, printCtx.parameters()); int g = printCtx.parameters().getGap(); String fmt = "%" + asBlankArg(g) + "s%s"; @@ -95,7 +97,7 @@ final class StringVectorPrinter extends VectorPrinter<RAbstractStringVector> { } } - static int formatString(RAbstractStringVector x, int offs, int n, boolean quote, PrintParameters pp) { + static int formatString(RandomIterator iter, VectorAccess access, int offs, int n, boolean quote, PrintParameters pp) { int xmax = 0; int l; @@ -103,7 +105,7 @@ final class StringVectorPrinter extends VectorPrinter<RAbstractStringVector> { int fieldwidth; for (int i = 0; i < n; i++) { - String s = x.getDataAt(offs + i); + String s = access.getString(iter, offs + i); String xi = RRuntime.escapeString(s, false, quote); if (xi == RRuntime.STRING_NA) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java index e2a12e3ae18c0977f6db8c47300dac10950c6080..4a97ef3b3c4ec5e5cbd0ce13ce951147906e4848 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/VectorPrinter.java @@ -24,6 +24,8 @@ import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; 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.RandomIterator; //Transcribed from GnuR, src/main/print.c, src/main/printarray.c, src/main/printvector.c @@ -35,7 +37,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri } public void printVector(T vector, int indx, PrintContext printCtx) throws IOException { - createJob(vector, indx, printCtx).print(); + createJob(vector, indx, printCtx).print(vector); } protected abstract VectorPrintJob createJob(T vector, int indx, PrintContext printCtx); @@ -53,7 +55,8 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri protected abstract class VectorPrintJob { - protected final T vector; + protected VectorAccess access; + protected RandomIterator iterator; protected final int n; protected final int nPr; protected final int indx; @@ -69,13 +72,13 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri protected final boolean supressIndexLabels; protected VectorPrintJob(T vector, int indx, PrintContext printCtx) { - this.vector = vector; this.indx = indx; this.quote = printCtx.parameters().getQuote(); MatrixDimNames mdn = null; Object dimAttr = getDims(vector); + int length = vector.getLength(); if (dimAttr instanceof RAbstractIntVector) { dims = (RAbstractIntVector) dimAttr; if (dims.getLength() == 1) { @@ -89,12 +92,12 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri title = null; } - jobMode = vector.getLength() == 0 ? JobMode.namedEmpty : JobMode.named; + jobMode = length == 0 ? JobMode.namedEmpty : JobMode.named; names = Utils.castTo(RRuntime.convertScalarVectors(t.getDataAt(0))); } else { title = null; names = null; - jobMode = vector.getLength() == 0 ? JobMode.empty : JobMode.nonEmpty; + jobMode = length == 0 ? JobMode.empty : JobMode.nonEmpty; } } else if (dims.getLength() == 2) { mdn = new MatrixDimNames(vector); @@ -111,14 +114,14 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri dims = null; Object namesAttr = Utils.castTo(getNames(vector)); if (namesAttr != null) { - if (vector.getLength() > 0) { + if (length > 0) { names = Utils.castTo(RRuntime.convertScalarVectors(namesAttr)); jobMode = JobMode.named; } else { names = null; jobMode = JobMode.namedEmpty; } - } else if (vector.getLength() > 0) { + } else if (length > 0) { jobMode = JobMode.nonEmpty; names = null; } else { @@ -134,32 +137,36 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri this.printCtx.parameters().setRight(true); } this.out = this.printCtx.output(); - this.n = vector.getLength(); + this.n = length; int max = printCtx.parameters().getMax(); this.nPr = (n <= max + 1) ? n : max; this.labwidth = indexWidth(n) + 2; this.matrixDimNames = mdn; } - public void print() throws IOException { - switch (jobMode) { - case empty: - printEmptyVector(); - break; - case nonEmpty: - printNonEmptyVector(); - break; - case named: - printNamedVector(); - break; - case namedEmpty: - printNamedEmptyVector(); - break; - case matrix: - printMatrix(); - break; - case array: - printArray(); + public final void print(T vector) throws IOException { + access = vector.access(); + try (RandomIterator iter = access.randomAccess(vector)) { + this.iterator = iter; + switch (jobMode) { + case empty: + printEmptyVector(); + break; + case nonEmpty: + printNonEmptyVector(); + break; + case named: + printNamedVector(); + break; + case namedEmpty: + printNamedEmptyVector(); + break; + case matrix: + printMatrix(); + break; + case array: + printArray(); + } } } @@ -209,7 +216,10 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri PrintParameters pp = printCtx.parameters(); - wn = StringVectorPrinter.formatString(names, 0, n, false, pp); + VectorAccess namesAccess = names.slowPathAccess(); + try (RandomIterator namesIter = namesAccess.randomAccess(names)) { + wn = StringVectorPrinter.formatString(namesIter, namesAccess, 0, n, false, pp); + } if (fm.maxWidth < wn) { fm.maxWidth = wn; } @@ -302,7 +312,10 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri int lbloff = 0; if (rl != null) { - rlabw = StringVectorPrinter.formatString(rl, 0, r, false, pp); + VectorAccess rlAccess = rl.slowPathAccess(); + try (RandomIterator rlIter = rlAccess.randomAccess(rl)) { + rlabw = StringVectorPrinter.formatString(rlIter, rlAccess, 0, r, false, pp); + } } else { rlabw = indexWidth(r + 1) + 3; } @@ -609,9 +622,9 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri protected abstract void printElement(int i, FormatMetrics fm) throws IOException; private void printElementAndNotify(int i, FormatMetrics fm) throws IOException { - out.beginElement(vector, i, fm); + out.beginElement(i, fm); printElement(i, fm); - out.endElement(vector, i, fm); + out.endElement(i, fm); } /** @@ -625,9 +638,9 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri protected abstract void printCell(int i, FormatMetrics fm) throws IOException; private void printCellAndNotify(int i, FormatMetrics fm) throws IOException { - out.beginElement(vector, i, fm); + out.beginElement(i, fm); printCell(i, fm); - out.endElement(vector, i, fm); + out.endElement(i, fm); } protected int matrixIndividualCellColumnWidthCorrection() { @@ -713,7 +726,7 @@ abstract class VectorPrinter<T extends RAbstractVector> extends AbstractValuePri } @TruffleBoundary - private static Object getNames(RAbstractVector vector) { - return vector.getAttr(RRuntime.NAMES_ATTR_KEY); + private static Object getNames(RAbstractVector x) { + return x.getAttr(RRuntime.NAMES_ATTR_KEY); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java index 1b211974b3c9f8ab72cb4d8711e76a132876cfe3..9f6f6652e1d19533b225ea5e3afe6c2943211587 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/RASTBuilder.java @@ -258,15 +258,14 @@ public final class RASTBuilder implements RCodeBuilder<RSyntaxNode> { public RSyntaxNode constant(SourceSection source, Object value) { if (value instanceof String && !RRuntime.isNA((String) value)) { return ConstantNode.create(source, Utils.intern((String) value)); - } else { - if (value instanceof RShareable) { - RShareable shareable = (RShareable) value; - if (!shareable.isSharedPermanent()) { - return ConstantNode.create(source, shareable.makeSharedPermanent()); - } + } + if (value instanceof RShareable) { + RShareable shareable = (RShareable) value; + if (!shareable.isSharedPermanent()) { + return ConstantNode.create(source, shareable.makeSharedPermanent()); } - return ConstantNode.create(source, value); } + return ConstantNode.create(source, value); } @Override diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java index 903947939fed214361eb750ec927e7f480a2c503..4ab4126616010c6acaae4d804942752ec14601e6 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedExtractVectorNode.java @@ -39,10 +39,8 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNa import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimNamesAttributeNode; -import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; -import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.context.RContext; @@ -52,8 +50,6 @@ import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RLogical; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RPromise; -import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RString; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RTypedValue; @@ -61,7 +57,6 @@ import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.nodes.RBaseNode; final class CachedExtractVectorNode extends CachedVectorNode { @@ -69,7 +64,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { private static final boolean DEFAULT_EXACT = true; private static final boolean DEFAULT_DROP_DIMENSION = true; - private final Class<? extends RTypedValue> targetClass; + private final Class<? extends RAbstractContainer> targetClass; private final Class<? extends RTypedValue> exactClass; private final Class<? extends RTypedValue> dropDimensionsClass; private final boolean exact; @@ -90,10 +85,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { @Child private ExtractDimNamesNode extractDimNames; - @Child private ExtractS4ObjectNode extractS4ObjectNode; - private final ConditionProfile resultHasDimensions = ConditionProfile.createBinaryProfile(); - private final ConditionProfile promiseInEnvironment = ConditionProfile.createBinaryProfile(); /** * Profile if any metadata was applied at any point in time. This is useful extract primitive @@ -101,8 +93,9 @@ final class CachedExtractVectorNode extends CachedVectorNode { */ private final AlwaysOnBranchProfile metadataApplied = AlwaysOnBranchProfile.create(); - CachedExtractVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, RTypedValue exact, RTypedValue dropDimensions, boolean recursive) { + CachedExtractVectorNode(ElementAccessMode mode, RAbstractContainer vector, Object[] positions, RTypedValue exact, RTypedValue dropDimensions, boolean recursive) { super(mode, vector, positions, recursive); + assert vectorType != RType.Null && vectorType != RType.Environment; this.targetClass = vector.getClass(); this.exactClass = exact.getClass(); this.dropDimensionsClass = dropDimensions.getClass(); @@ -112,9 +105,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { this.exact = logicalAsBoolean(exact, DEFAULT_EXACT); this.dropDimensions = logicalAsBoolean(dropDimensions, DEFAULT_DROP_DIMENSION); this.positionsCheckNode = new PositionsCheckNode(mode, vectorType, convertedPositions, this.exact, false, recursive); - if (error == null && vectorType != RType.Null && vectorType != RType.Environment && vectorType != RType.S4Object) { - this.writeVectorNode = WriteIndexedVectorNode.create(vectorType, convertedPositions.length, true, false, false, false); - } + this.writeVectorNode = WriteIndexedVectorNode.create(vectorType, convertedPositions.length, true, false, false); } public boolean isSupported(Object target, Object[] positions, Object exactValue, Object dropDimensionsValue) { @@ -130,36 +121,10 @@ final class CachedExtractVectorNode extends CachedVectorNode { private final ConditionProfile extractedLengthGTZeroProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile oneDimensionProfile = ConditionProfile.createBinaryProfile(); - public Object apply(Object originalVector, Object[] originalPositions, PositionProfile[] originalProfiles, Object originalExact, Object originalDropDimensions) { - if (error != null) { - CompilerDirectives.transferToInterpreter(); - error.run(); - } + public Object apply(RAbstractContainer originalVector, Object[] originalPositions, PositionProfile[] originalProfiles, Object originalExact, Object originalDropDimensions) { final Object[] positions = filterPositions(originalPositions); - assert isSupported(originalVector, positions, originalExact, originalDropDimensions); - - final RTypedValue castVector = targetClass.cast(originalVector); - final RAbstractContainer vector; - switch (vectorType) { - case Null: - return RNull.instance; - case Environment: - /* - * TODO (chumer) the environment case cannot be applied to the default extract - * method as it does not implement RAbstractContainer. This should be harmonized - * later. - */ - return doEnvironment((REnvironment) castVector, positions); - case S4Object: - return doS4Object((RS4Object) castVector, positions); - case Integer: - vector = (RAbstractContainer) castVector; - break; - default: - vector = (RAbstractContainer) castVector; - break; - } + RAbstractContainer vector = targetClass.cast(originalVector); int vectorLength = vectorLengthProfile.profile(vector.getLength()); @@ -178,11 +143,8 @@ final class CachedExtractVectorNode extends CachedVectorNode { } int extractedVectorLength = positionsCheckNode.getSelectedPositionsCount(positionProfiles); - final RVector<?> extractedVector; + RVector<?> extractedVector; switch (vectorType) { - case Expression: - extractedVector = RType.Expression.create(extractedVectorLength, false); - break; case Language: case PairList: extractedVector = RType.List.create(extractedVectorLength, false); @@ -194,9 +156,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { if (mode.isSubset()) { if (extractedLengthGTZeroProfile.profile(extractedVectorLength > 0)) { - writeVectorNode.enableValueNACheck(vector); - writeVectorNode.apply(extractedVector, extractedVectorLength, positions, vector, vectorLength, dimensions); - extractedVector.setComplete(writeVectorNode.neverSeenNAInValue()); + writeVectorNode.execute(extractedVector, positions, vector, dimensions); RBaseNode.reportWork(this, extractedVectorLength); } if (oneDimensionProfile.profile(numberOfDimensions == 1)) { @@ -216,15 +176,13 @@ final class CachedExtractVectorNode extends CachedVectorNode { } switch (vectorType) { - case Expression: - return extractedVector; case Language: return materializeLanguage(extractedVector); default: return trySubsetPrimitive(extractedVector); } } else { - writeVectorNode.apply(extractedVector, extractedVectorLength, positions, vector, vectorLength, dimensions); + writeVectorNode.execute(extractedVector, positions, vector, dimensions); RBaseNode.reportWork(this, 1); assert extractedVectorLength == 1; return extractedVector.getDataAtAsObject(0); @@ -242,7 +200,7 @@ final class CachedExtractVectorNode extends CachedVectorNode { } private Object trySubsetPrimitive(RAbstractVector extractedVector) { - if (!metadataApplied.isVisited() && positionsCheckNode.getCachedSelectedPositionsCount() == 1 && !isList()) { + if (!metadataApplied.isVisited() && positionsCheckNode.getCachedSelectedPositionsCount() == 1 && vectorType != RType.List && vectorType != RType.Expression) { /* * If the selected count was always 1 and no metadata was ever set we can just extract * the primitive value from the vector. This branch has to fold to a constant because we @@ -256,31 +214,6 @@ final class CachedExtractVectorNode extends CachedVectorNode { return extractedVector; } - @TruffleBoundary - private Object doEnvironment(REnvironment env, Object[] positions) { - if (mode.isSubset()) { - throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName()); - } - - String positionString = tryCastSingleString(positionsCheckNode, positions); - if (positionString != null) { - Object obj = env.get(positionString); - if (promiseInEnvironment.profile(obj instanceof RPromise)) { - obj = PromiseHelperNode.evaluateSlowPath((RPromise) obj); - } - return obj == null ? RNull.instance : obj; - } - throw error(RError.Message.WRONG_ARGS_SUBSET_ENV); - } - - private Object doS4Object(RS4Object object, Object[] positions) { - if (extractS4ObjectNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - extractS4ObjectNode = insert(new ExtractS4ObjectNode(mode, exact, dropDimensions)); - } - return extractS4ObjectNode.execute(object, positions); - } - private boolean isMissingSingleDimension() { return numberOfDimensions == 1 && positionsCheckNode.isMissing(); } @@ -298,10 +231,6 @@ final class CachedExtractVectorNode extends CachedVectorNode { return extractDimNames.extract(dimensionIndex, vector, pos, profile); } - private boolean isList() { - return vectorType == RType.List; - } - private final ConditionProfile dimNamesNull = ConditionProfile.createBinaryProfile(); private final ValueProfile foundDimNamesProfile = ValueProfile.createClassProfile(); private final ConditionProfile selectPositionsProfile = ConditionProfile.createBinaryProfile(); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java index 40e456bf6c06a3da980ffc7cf9054e56d682aaef..43e9de314e70a6237d6060d7e6b55e63ba6e5abf 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedReplaceVectorNode.java @@ -34,7 +34,6 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; -import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; @@ -49,15 +48,11 @@ import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RPairList; -import com.oracle.truffle.r.runtime.data.RS4Object; +import com.oracle.truffle.r.runtime.data.RScalarList; import com.oracle.truffle.r.runtime.data.RScalarVector; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -66,27 +61,22 @@ import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import com.oracle.truffle.r.runtime.env.REnvironment; -import com.oracle.truffle.r.runtime.env.REnvironment.PutException; import com.oracle.truffle.r.runtime.nodes.RBaseNode; final class CachedReplaceVectorNode extends CachedVectorNode { private static final Object DELETE_MARKER = new Object(); - private final Class<?> vectorClass; + private final Class<? extends RAbstractVector> vectorClass; private final Class<?> valueClass; private final VectorLengthProfile targetLengthProfile = VectorLengthProfile.create(); private final VectorLengthProfile valueLengthProfile = VectorLengthProfile.create(); private final BranchProfile warningBranch = BranchProfile.create(); - private final ConditionProfile valueIsNA = ConditionProfile.createBinaryProfile(); private final BranchProfile resizeProfile = BranchProfile.create(); - private final ConditionProfile rlanguageAttributesProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile valueLengthOneProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile emptyReplacementProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile completeVectorProfile = ConditionProfile.createBinaryProfile(); private final ValueProfile vectorTypeProfile = ValueProfile.createClassProfile(); @@ -103,9 +93,13 @@ final class CachedReplaceVectorNode extends CachedVectorNode { @Child private DeleteElementsNode deleteElementsNode; @Child private SetNamesAttributeNode setNamesNode; - CachedReplaceVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, Class<?> valueClass, RType valueType, boolean updatePositionNames, boolean recursive, - boolean ignoreRecursive, boolean isValueGt1) { + // if this is non-null, the node needs to throw the error whenever it is executed + @CompilationFinal protected Runnable error; + + CachedReplaceVectorNode(ElementAccessMode mode, RAbstractVector vector, Object[] positions, Class<?> valueClass, RType valueType, boolean updatePositionNames, boolean recursive, + boolean isValueGt1) { super(mode, vector, positions, recursive); + assert vectorType.isVector(); if (numberOfDimensions == 1 && positions[0] instanceof String || positions[0] instanceof RAbstractStringVector) { this.updatePositionNames = updatePositionNames; @@ -117,17 +111,48 @@ final class CachedReplaceVectorNode extends CachedVectorNode { this.valueClass = valueClass; this.valueType = valueType; this.isValueGt1 = isValueGt1; - this.castType = resolveCastVectorType(); - verifyCastType(this.castType); - this.castVectorNode = createCastVectorNode(); + + // determine the target cast type + if (vectorType == RType.List && mode.isSubscript()) { + if (valueType.isNull() && numberOfDimensions > 1) { + this.castType = null; + } else { + this.castType = vectorType; + } + } else if (valueType.isVector()) { + if (vectorType.isAtomic() && valueType.isAtomic() && (vectorType == RType.Raw ^ valueType == RType.Raw)) { + // mixing with raw with other atomic types is not allowed + this.castType = null; + } else { + this.castType = RType.maxPrecedence(valueType, vectorType); + } + } else if (valueType.isNull()) { + if (mode.isSubscript() && numberOfDimensions > 1) { + this.castType = null; + } else { + this.castType = vectorType; + } + } else { + this.castType = null; + } + + if (castType == null) { + Message message = (mode.isSubset() || vectorType != RType.List) ? RError.Message.SUBASSIGN_TYPE_FIX : RError.Message.SUBSCRIPT_TYPES; + error = () -> { + throw error(message, valueType.getName(), vectorType.getName(), false); + }; + } + + if (castType != vectorType && castType != null) { + // All casts except list casts preserve dimension names. + this.castVectorNode = castType == RType.List ? CastListNodeGen.create(true, false, true) : CastTypeNode.createCast(castType, true, true, true, false); + } this.deleteElementsNode = isDeleteElements() ? new DeleteElementsNode() : null; Object[] convertedPositions = filterPositions(positions); this.positionsCheckNode = new PositionsCheckNode(mode, vectorType, convertedPositions, true, true, recursive); - if (vectorType == RType.S4Object) { - replaceS4ObjectNode = new ReplaceS4ObjectNode(mode, ignoreRecursive); - } else if (castType != null && !castType.isNull()) { - this.writeVectorNode = WriteIndexedVectorNode.create(castType, convertedPositions.length, false, true, mode.isSubscript() && !isDeleteElements(), true); + if (castType != null && !castType.isNull()) { + this.writeVectorNode = WriteIndexedVectorNode.create(castType, convertedPositions.length, false, true, true); } } @@ -135,50 +160,41 @@ final class CachedReplaceVectorNode extends CachedVectorNode { return (values instanceof RAbstractContainer) && ((RAbstractContainer) values).getLength() > 1; } - public boolean isSupported(Object target, Object[] positions, Object values) { + public boolean isSupported(RAbstractVector target, Object[] positions, Object values) { if (vectorClass == target.getClass() && values.getClass() == valueClass) { return positionsCheckNode.isSupported(positions) && isValueLengthGreaterThanOne(values) == isValueGt1; } return false; } - public Object apply(Object originalVector, Object[] originalPositions, Object originalValues) { + public Object apply(RAbstractVector originalVector, Object[] originalPositions, Object originalValues) { if (error != null) { CompilerDirectives.transferToInterpreter(); error.run(); } - final Object[] positions = filterPositions(originalPositions); + Object[] positions = filterPositions(originalPositions); assert isSupported(originalVector, positions, originalValues); - Object castVector = vectorClass.cast(originalVector); + RAbstractVector vector = vectorClass.cast(originalVector); Object castValue = valueClass.cast(originalValues); - if (vectorType == RType.Environment) { - return doEnvironment((REnvironment) castVector, positions, castValue); - } else if (vectorType == RType.S4Object) { - return doS4Object((RS4Object) castVector, positions, castValue); - } - - Object value; + RAbstractContainer value; if (valueType == RType.Null) { - if (vectorType == RType.Null) { - // we cast Null to Logical, but in the end it will fold and return Null - value = RType.Logical.getEmpty(); - } else if (castType == RType.List) { + if (castType == RType.List) { value = RDataFactory.createList(new Object[]{DELETE_MARKER}); } else { value = castType.getEmpty(); } } else { - value = castValue; + if ((castType == RType.List || castType == RType.Expression) && mode.isSubscript() && !isDeleteElements() && !(castValue instanceof RScalarVector)) { + // wrap into a list when + value = RScalarList.valueOf(castValue); + } else { + value = (RAbstractContainer) castValue; + } } - int appliedValueLength; - if (value instanceof RAbstractContainer) { - appliedValueLength = valueLengthProfile.profile(((RAbstractContainer) value).getLength()); - } else { - appliedValueLength = 1; - } + int appliedValueLength = valueLengthProfile.profile(value.getLength()); int valueLength; if (this.numberOfDimensions > 1 && isDeleteElements()) { @@ -187,39 +203,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode { valueLength = appliedValueLength; } - if (vectorType == RType.Null) { - if (valueLength == 0) { - return RNull.instance; - } - } - - /* - * Unfortunately special behavior for some RTypes are necessary. We should aim for getting - * rid of them as much as possible in the future. N.B.: because of this 'unwrapping' any - * return should call wrapResult(vector, repType) to do the reverse where necessary. - */ - RAbstractVector vector; - RLanguage.RepType repType = RLanguage.RepType.UNKNOWN; - switch (vectorType) { - case Null: - vector = castType.getEmpty(); - break; - case PairList: - vector = ((RPairList) castVector).toRList(); - break; - case Language: - repType = RContext.getRRuntimeASTAccess().getRepType((RLanguage) castVector); - vector = RContext.getRRuntimeASTAccess().asList((RLanguage) castVector); - DynamicObject attrs = ((RLanguage) castVector).getAttributes(); - if (rlanguageAttributesProfile.profile(attrs != null && !attrs.isEmpty())) { - vector.initAttributes(RAttributesLayout.copy(attrs)); - } - break; - default: - vector = (RAbstractVector) castVector; - break; - } - int vectorLength = targetLengthProfile.profile(vector.getLength()); int[] vectorDimensions; if (numberOfDimensions == 1) { @@ -238,29 +221,30 @@ final class CachedReplaceVectorNode extends CachedVectorNode { int replacementLength = positionsCheckNode.getSelectedPositionsCount(positionProfiles); if (emptyReplacementProfile.profile(replacementLength == 0)) { - /* Nothing to modify */ - if (vectorType == RType.Language || vectorType == RType.Expression) { - return originalVector; - } else { - return vector.materialize(); - } + // Nothing to modify + return vector; } if (valueLengthOneProfile.profile(valueLength != 1)) { verifyValueLength(positionProfiles, valueLength); } - - if (!isList() && value instanceof RAbstractVector) { - value = ((RAbstractVector) value).castSafe(castType, valueIsNA, false); + if (vector instanceof RShareable) { + RShareable shareable = (RShareable) vector; + // TODO find out if we need to copy always in the recursive case + if (recursive || sharedConditionProfile.execute(shareable.isShared()) || valueEqualsVectorProfile.profile(vector == value)) { + shareable = (RShareable) vector.copy(); + vector = (RAbstractVector) shareable; + assert shareable.isTemporary(); + } } - - vector = share(vector, value); + vector = sharedClassProfile.profile(vector); + CompilerAsserts.partialEvaluationConstant(vector.getClass()); int maxOutOfBounds = positionsCheckNode.getMaxOutOfBounds(positionProfiles); if (maxOutOfBounds > vectorLength) { resizeProfile.enter(); if (isDeleteElements() && mode.isSubscript()) { - return wrapResult(vector, repType); + return vector; } vector = resizeVector(vector, maxOutOfBounds); } else { @@ -297,17 +281,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode { } } - if (value instanceof RAbstractContainer) { - writeVectorNode.enableValueNACheck((RAbstractContainer) value); - } - - writeVectorNode.apply(vector, vectorLength, positions, value, appliedValueLength, vectorDimensions); - boolean complete = vector.isComplete(); - if (completeVectorProfile.profile(complete)) { - if (!writeVectorNode.neverSeenNAInValue()) { - vector.setComplete(false); - } - } + writeVectorNode.execute(vector, positions, value, vectorDimensions); RBaseNode.reportWork(this, replacementLength); @@ -320,48 +294,7 @@ final class CachedReplaceVectorNode extends CachedVectorNode { updateVectorWithPositionNames(vector, positions); } - return wrapResult(vector, repType); - } - - private Object wrapResult(RAbstractVector vector, RLanguage.RepType repType) { - switch (vectorType) { - case Language: - return RContext.getRRuntimeASTAccess().createLanguageFromList((RList) vector, repType); - default: - return vector; - } - } - - private void verifyCastType(RType compatibleType) { - if (error == null && compatibleType == null && (vectorType.isNull() || vectorType.isVector())) { - Message message; - if (mode.isSubset()) { - message = RError.Message.SUBASSIGN_TYPE_FIX; - } else { - if (vectorType == RType.List) { - message = RError.Message.SUBSCRIPT_TYPES; - } else { - message = RError.Message.SUBASSIGN_TYPE_FIX; - } - } - error = () -> { - throw error(message, valueType.getName(), vectorType.getName(), false); - }; - } - } - - private CastNode createCastVectorNode() { - if (castType == vectorType || castType == null || castType == RType.Null) { - return null; - } - /* - * All casts except list casts preserve dimension names. - */ - if (castType == RType.List) { - return CastListNodeGen.create(true, false, true); - } else { - return CastTypeNode.createCast(castType, true, true, true, false); - } + return vector; } private boolean isDeleteElements() { @@ -372,54 +305,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode { return castType == RType.List; } - private RType resolveCastVectorType() { - final RType vector; - // convert type for list like values - switch (this.vectorType) { - case Language: - case Expression: - case PairList: - vector = RType.List; - break; - case Environment: - vector = RType.List; - break; - default: - vector = this.vectorType; - break; - } - - RType value = this.valueType; - - if (vector == RType.List && mode.isSubscript()) { - if (value.isNull() && numberOfDimensions > 1) { - return null; - } else { - return vector; - } - } else if (vector.isVector() && value.isVector()) { - if (vector != value) { - if (vector == RType.List || value == RType.List) { - return RType.List; - } - if (vector == RType.Raw || value == RType.Raw) { - return null; - } - } - return RType.maxPrecedence(value, vector); - } else if (vector.isNull() || value.isNull()) { - if (!value.isNull()) { - return (mode == ElementAccessMode.FIELD_SUBSCRIPT || (mode == ElementAccessMode.SUBSCRIPT && isValueGt1)) ? RType.List : value; - } - if (mode.isSubscript() && numberOfDimensions > 1) { - return null; - } - return vector; - } else { - return null; - } - } - private void verifyValueLength(PositionProfile[] positionProfiles, int valueLength) { if (mode.isSubscript()) { if (!isList()) { @@ -469,34 +354,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode { } } - private Object doEnvironment(REnvironment env, Object[] positions, Object originalValues) { - if (mode.isSubset()) { - throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName()); - } - - String positionString = tryCastSingleString(positionsCheckNode, positions); - if (positionString == null) { - throw error(RError.Message.WRONG_ARGS_SUBSET_ENV); - } - - try { - Object value = originalValues; - if (value instanceof RScalarVector) { - value = ((RScalarVector) value).getDataAtAsObject(0); - } - env.put(positionString, value); - } catch (PutException ex) { - throw error(ex); - } - return env; - } - - @Child private ReplaceS4ObjectNode replaceS4ObjectNode; - - private Object doS4Object(RS4Object obj, Object[] positions, Object originalValues) { - return replaceS4ObjectNode.execute(obj, positions, originalValues); - } - @NodeInfo(cost = NONE) public abstract static class ValueProfileNode extends Node { @@ -520,28 +377,6 @@ final class CachedReplaceVectorNode extends CachedVectorNode { private final ConditionProfile valueEqualsVectorProfile = ConditionProfile.createBinaryProfile(); - /* - * TODO (chumer) share code between {@link #share(RAbstractVector)} and {@link - * #copyValueOnAssignment(RAbstractContainer)} - */ - private RAbstractVector share(RAbstractVector vector, Object value) { - RAbstractVector returnVector = vector; - if (returnVector instanceof RShareable) { - RShareable shareable = (RShareable) returnVector; - // TODO find out if we need to copy always in the recursive case - if (recursive || sharedConditionProfile.execute(shareable.isShared()) || valueEqualsVectorProfile.profile(vector == value)) { - shareable = (RShareable) returnVector.copy(); - returnVector = (RAbstractVector) shareable; - assert shareable.isTemporary(); - } - } - returnVector = sharedClassProfile.profile(returnVector); - - CompilerAsserts.partialEvaluationConstant(returnVector.getClass()); - - return returnVector; - } - // TODO (chumer) this is way to complicated at the moment // not yet worth compiling. we should introduce some nodes for this @TruffleBoundary diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java index 595c1452ef73f1fe6d3acff813ca57342c6b85fa..d9346356426458ac2c92f71dc664a4a5c7780476 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/CachedVectorNode.java @@ -22,9 +22,7 @@ */ package com.oracle.truffle.r.nodes.access.vector; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; -import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RMissing; @@ -56,9 +54,6 @@ abstract class CachedVectorNode extends RBaseNode { protected final int numberOfDimensions; private final int filteredPositionsLength; - // if this is non-null, the node needs to throw the error whenever it is executed - @CompilationFinal protected Runnable error; - @Child private GetDimAttributeNode getDimNode = GetDimAttributeNode.create(); CachedVectorNode(ElementAccessMode mode, RTypedValue vector, Object[] positions, boolean recursive) { @@ -71,11 +66,6 @@ abstract class CachedVectorNode extends RBaseNode { } else { this.numberOfDimensions = filteredPositionsLength; } - if (!isSubsetable(vectorType)) { - error = () -> { - throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, vectorType.getName()); - }; - } } private static int initializeFilteredPositionsCount(Object[] positions) { @@ -136,23 +126,6 @@ abstract class CachedVectorNode extends RBaseNode { } } - private static boolean isSubsetable(RType type) { - if (type.isVector()) { - return true; - } - switch (type) { - case Null: - case Language: - case PairList: - case Environment: - case Expression: - case S4Object: - return true; - default: - return false; - } - } - protected final int[] loadVectorDimensions(RAbstractContainer vector) { // N.B. (stepan) this method used to be instance method and have special handling for // RDataFrame, which was removed and any test case, which would require this special diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java deleted file mode 100644 index 70df3131589553daab5ed53561f33f4a2fb20d76..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractS4ObjectNode.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.nodes.access.vector; - -import static com.oracle.truffle.r.runtime.RError.Message.OP_NOT_DEFINED_FOR_S4_CLASS; - -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen; -import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RS4Object; -import com.oracle.truffle.r.runtime.data.RTypedValue; -import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; - -public class ExtractS4ObjectNode extends Node { - @Child private GetS4DataSlot getS4DataSlotNode = GetS4DataSlotNodeGen.create(RType.Environment); - @Child private ExtractVectorNode extract; - private final boolean exact; - private final boolean dropDimensions; - - public ExtractS4ObjectNode(ElementAccessMode accessMode, boolean exact, boolean dropDimensions) { - this.extract = ExtractVectorNode.create(accessMode, true); - this.exact = exact; - this.dropDimensions = dropDimensions; - } - - public Object execute(RS4Object obj, Object[] positions) { - RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj); - if (dataSlot == RNull.instance) { - throw RError.error(RError.SHOW_CALLER, OP_NOT_DEFINED_FOR_S4_CLASS, "$"); - } - return extract.execute(dataSlot, positions, createLogical(exact), createLogical(dropDimensions)); - } - - private static RAbstractLogicalVector createLogical(boolean b) { - return RDataFactory.createLogicalVectorFromScalar(b); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java index c3c7bcbd3519ee7244320a1c1d471a046e007950..54338db024c2be03c583839f28bf8b77641bb133 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java @@ -23,8 +23,10 @@ package com.oracle.truffle.r.nodes.access.vector; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.ForeignAccess; @@ -34,20 +36,31 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNodeGen.ExtractSingleNameNodeGen; import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode; +import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; +import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; +import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.FirstStringNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RLogical; import com.oracle.truffle.r.runtime.data.RMissing; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; 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.RAbstractListVector; 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.RandomIterator; +import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.interop.Foreign2R; import com.oracle.truffle.r.runtime.interop.ForeignArray2R; import com.oracle.truffle.r.runtime.interop.ForeignArray2R.ForeignArrayData; @@ -58,7 +71,7 @@ public abstract class ExtractVectorNode extends RBaseNode { protected static final int CACHE_LIMIT = 5; - private final ElementAccessMode mode; + protected final ElementAccessMode mode; private final boolean recursive; private final boolean ignoreRecursive; @@ -124,23 +137,92 @@ public abstract class ExtractVectorNode extends RBaseNode { } @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions, exact, dropDimensions)"}) - protected Object doExtractDefaultCached(Object vector, Object[] positions, Object exact, Object dropDimensions, // + protected Object doExtractDefaultCached(RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions, // @Cached("createDefaultCache(getThis(), vector, positions, exact, dropDimensions)") CachedExtractVectorNode cached) { assert !isRecursiveSubscript(vector, positions); return cached.apply(vector, positions, null, exact, dropDimensions); } - protected static CachedExtractVectorNode createDefaultCache(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) { - return new CachedExtractVectorNode(node.getMode(), (RTypedValue) vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive); + protected static CachedExtractVectorNode createDefaultCache(ExtractVectorNode node, RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions) { + assert !(vector instanceof REnvironment); + return new CachedExtractVectorNode(node.getMode(), vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive); } - @Specialization(replaces = "doExtractDefaultCached", guards = "!isForeignObject(vector)") + @Specialization(replaces = "doExtractDefaultCached", guards = {"!isForeignObject(vector)"}) @TruffleBoundary - protected Object doExtractDefaultGeneric(Object vector, Object[] positions, Object exact, Object dropDimensions, // + protected Object doExtractDefaultGeneric(RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions, // @Cached("new(createDefaultCache(getThis(), vector, positions, exact, dropDimensions))") GenericVectorExtractNode generic) { return generic.get(this, vector, positions, exact, dropDimensions).apply(vector, positions, null, exact, dropDimensions); } + @Specialization + protected Object doExtractEnvironment(REnvironment env, Object[] positions, @SuppressWarnings("unused") Object exact, @SuppressWarnings("unused") Object dropDimensions, + @Cached("createExtractName()") ExtractSingleName extractName, + @Cached("new()") PromiseCheckHelperNode promiseHelper) { + if (mode.isSubset()) { + throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName()); + } + String name = positions.length == 1 ? extractName.execute(positions[0]) : null; + if (name != null) { + Object obj = env.get(name); + return obj == null ? RNull.instance : promiseHelper.checkEvaluate(null, obj); + } + throw error(RError.Message.WRONG_ARGS_SUBSET_ENV); + } + + @Specialization + protected Object doExtractS4Object(RS4Object obj, Object[] positions, Object exact, Object dropDimensions, + @Cached("createEnvironment()") GetS4DataSlot getS4DataSlotNode, + @Cached("create(mode, True)") ExtractVectorNode recursiveExtract) { + RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj); + if (dataSlot == RNull.instance) { + throw RError.error(RError.SHOW_CALLER, RError.Message.OP_NOT_DEFINED_FOR_S4_CLASS, "$"); + } + return recursiveExtract.execute(dataSlot, positions, exact, dropDimensions); + } + + abstract static class ExtractSingleName extends Node { + + public abstract String execute(Object value); + + public static ExtractSingleName createExtractName() { + return ExtractSingleNameNodeGen.create(); + } + + @Specialization + protected static String extract(String value) { + return value; + } + + @Specialization(guards = "access.supports(value)") + protected static String extractCached(RAbstractStringVector value, + @Cached("value.access()") VectorAccess access) { + try (RandomIterator iter = access.randomAccess(value)) { + if (access.getLength(iter) == 1) { + return access.getString(iter, 0); + } + } + return null; + } + + @Specialization(replaces = "extractCached") + @TruffleBoundary + protected static String extractGeneric(RAbstractStringVector value) { + return extractCached(value, value.slowPathAccess()); + } + + @Fallback + protected static String extractFallback(@SuppressWarnings("unused") Object value) { + return null; + } + } + + @SuppressWarnings("unused") + @Specialization + protected Object doExtractRNull(RNull vector, Object[] positions, Object exact, Object dropDimensions) { + return RNull.instance; + } + // TODO hack until Truffle-DSL supports this. protected ExtractVectorNode getThis() { return this; @@ -154,7 +236,7 @@ public abstract class ExtractVectorNode extends RBaseNode { this.cached = insert(cachedOperation); } - public CachedExtractVectorNode get(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) { + public CachedExtractVectorNode get(ExtractVectorNode node, RAbstractContainer vector, Object[] positions, Object exact, Object dropDimensions) { CompilerAsserts.neverPartOfCompilation(); if (!cached.isSupported(vector, positions, exact, dropDimensions)) { cached = cached.replace(createDefaultCache(node, vector, positions, exact, dropDimensions)); @@ -251,4 +333,11 @@ public abstract class ExtractVectorNode extends RBaseNode { private static TruffleObject toJavaClass(TruffleObject obj) { return JavaInterop.toJavaClass(obj); } + + @SuppressWarnings("unused") + @Fallback + protected Object access(Object object, Object[] positions, Object exact, Object dropDimensions) { + CompilerDirectives.transferToInterpreter(); + throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, Predef.typeName().apply(object)); + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java deleted file mode 100644 index afc04f304e9af843de7d835e03a384c1e7808832..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceS4ObjectNode.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.nodes.access.vector; - -import static com.oracle.truffle.r.runtime.RError.Message.NO_METHOD_ASSIGNING_SUBSET_S4; - -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; -import com.oracle.truffle.r.nodes.objects.GetS4DataSlotNodeGen; -import com.oracle.truffle.r.runtime.RError; -import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RS4Object; -import com.oracle.truffle.r.runtime.data.RTypedValue; - -public class ReplaceS4ObjectNode extends Node { - @Child private GetS4DataSlot getS4DataSlotNode = GetS4DataSlotNodeGen.create(RType.Environment); - @Child private ReplaceVectorNode replaceVectorNode; - - public ReplaceS4ObjectNode(ElementAccessMode mode, boolean ignoreRecursive) { - replaceVectorNode = ReplaceVectorNode.create(mode, ignoreRecursive); - } - - public Object execute(RS4Object obj, Object[] positions, Object values) { - RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj); - if (dataSlot == RNull.instance) { - throw RError.error(RError.SHOW_CALLER, NO_METHOD_ASSIGNING_SUBSET_S4); - } - // No need to update the data slot, the value is env and they have reference semantics. - replaceVectorNode.execute(dataSlot, positions, values); - return obj; - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java index f295281ded9fb2cd67094d7e21c4367b724dcc31..9d78ec148542ba97349f5f5ee30a1ae1b22b24a3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java @@ -23,31 +23,49 @@ package com.oracle.truffle.r.nodes.access.vector; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.KeyInfo; -import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.r.nodes.access.vector.ExtractVectorNode.ExtractSingleName; import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode; +import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; +import com.oracle.truffle.r.nodes.objects.GetS4DataSlot; import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.FirstStringNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RAttributesLayout; +import com.oracle.truffle.r.runtime.data.RLanguage; +import com.oracle.truffle.r.runtime.data.RLanguage.RepType; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RPairList; +import com.oracle.truffle.r.runtime.data.RS4Object; +import com.oracle.truffle.r.runtime.data.RScalarVector; import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; 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.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; import com.oracle.truffle.r.runtime.interop.R2Foreign; -import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen; import com.oracle.truffle.r.runtime.nodes.RBaseNode; /** @@ -58,9 +76,9 @@ public abstract class ReplaceVectorNode extends RBaseNode { protected static final int CACHE_LIMIT = 5; - private final ElementAccessMode mode; + protected final ElementAccessMode mode; private final boolean recursive; - private final boolean ignoreRecursive; + protected final boolean ignoreRecursive; @Child private BoxPrimitiveNode boxVector = BoxPrimitiveNode.create(); @Child private BoxPrimitiveNode boxValue = BoxPrimitiveNode.create(); @@ -81,23 +99,177 @@ public abstract class ReplaceVectorNode extends RBaseNode { return ReplaceVectorNodeGen.create(mode, false, ignoreRecursive); } - static ReplaceVectorNode createRecursive(ElementAccessMode mode) { + protected static ReplaceVectorNode createRecursive(ElementAccessMode mode) { return ReplaceVectorNodeGen.create(mode, true, false); } - protected Node createForeignWrite(Object[] positions) { - if (positions.length != 1) { - throw error(RError.Message.GENERIC, "Invalid number positions for foreign access."); + private boolean isRecursiveSubscript(Object vector, Object[] positions) { + return !recursive && !ignoreRecursive && mode.isSubscript() && vector instanceof RAbstractListVector && positions.length == 1; + } + + protected RecursiveReplaceSubscriptNode createRecursiveCache(Object vector, Object[] positions) { + if (isRecursiveSubscript(vector, positions)) { + return RecursiveReplaceSubscriptNode.create((RAbstractListVector) vector, positions[0]); } - return Message.WRITE.createNode(); + return null; } - protected FirstStringNode createFirstString() { - return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access."); + @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions)"}) + protected Object doRecursive(RAbstractListVector vector, Object[] positions, Object value, // + @Cached("createRecursiveCache(vector, positions)") RecursiveReplaceSubscriptNode cached) { + return cached.apply(vector, positions, value); + } + + protected CachedReplaceVectorNode createDefaultCached(RAbstractVector vector, Object[] positions, Object value) { + if (vector instanceof RAbstractListVector && isRecursiveSubscript(vector, positions)) { + return null; + } + return new CachedReplaceVectorNode(mode, vector, positions, value.getClass(), RRuntime.isForeignObject(value) ? RType.TruffleObject : ((RTypedValue) value).getRType(), true, + recursive, CachedReplaceVectorNode.isValueLengthGreaterThanOne(value)); + } + + @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions, value)"}) + protected Object doReplaceCached(RAbstractVector vector, Object[] positions, Object value, // + @Cached("createDefaultCached(vector, positions, value)") CachedReplaceVectorNode cached) { + assert !isRecursiveSubscript(vector, positions); + return cached.apply(vector, positions, value); + } + + @Specialization + @TruffleBoundary + protected Object doReplaceEnvironment(REnvironment env, Object[] positions, Object value, + @Cached("createExtractName()") ExtractSingleName extractName) { + if (mode.isSubset()) { + throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, RType.Environment.getName()); + } + String name = positions.length == 1 ? extractName.execute(positions[0]) : null; + if (name != null) { + try { + env.put(name, value instanceof RScalarVector ? ((RScalarVector) value).getDataAtAsObject(0) : value); + } catch (PutException ex) { + throw error(ex); + } + } + return env; + } + + @Specialization + @TruffleBoundary + protected Object doReplaceS4Object(RS4Object obj, Object[] positions, Object value, + @Cached("createEnvironment()") GetS4DataSlot getS4DataSlotNode, + @Cached("create(mode, ignoreRecursive)") ReplaceVectorNode recursiveReplace) { + RTypedValue dataSlot = getS4DataSlotNode.executeObject(obj); + if (dataSlot == RNull.instance) { + throw RError.error(RError.SHOW_CALLER, RError.Message.NO_METHOD_ASSIGNING_SUBSET_S4); + } + // No need to update the data slot, the value is env and they have reference semantics. + recursiveReplace.execute(dataSlot, positions, value); + return obj; + } + + protected ReplaceVectorNode createForContainerTypes() { + return ReplaceVectorNodeGen.create(mode, false, false); + } + + @Specialization + protected Object doReplacementNull(@SuppressWarnings("unused") RNull vector, Object[] positions, Object value, + @Cached("createForContainerTypes()") ReplaceVectorNode replace) { + /* + * Replacing inside a variable containing NULL is quite inconsistent, we try to emulate the + * behavior as good as possible. + */ + if (value == RNull.instance) { + return RNull.instance; + } + RType type; + switch (mode) { + case FIELD_SUBSCRIPT: + type = RType.List; + break; + case SUBSCRIPT: + if (value instanceof RAbstractAtomicVector && ((RAbstractAtomicVector) value).getLength() == 1) { + type = ((RAbstractAtomicVector) value).getRType(); + } else { + type = RType.List; + } + break; + case SUBSET: + if (value instanceof RAbstractAtomicVector) { + if (((RAbstractAtomicVector) value).getLength() == 0) { + return RNull.instance; + } else { + type = ((RAbstractAtomicVector) value).getRType(); + } + } else { + type = RType.List; + } + break; + default: + throw RInternalError.shouldNotReachHere(); + } + return replace.execute(type.getEmpty(), positions, value); + } + + @Specialization + @TruffleBoundary + protected Object doReplacementLanguage(RLanguage vector, Object[] positions, Object value, + @Cached("createForContainerTypes()") ReplaceVectorNode replace) { + RepType repType = RContext.getRRuntimeASTAccess().getRepType(vector); + RList result = RContext.getRRuntimeASTAccess().asList(vector); + DynamicObject attrs = vector.getAttributes(); + if (attrs != null && !attrs.isEmpty()) { + result.initAttributes(RAttributesLayout.copy(attrs)); + } + result = (RList) replace.execute(result, positions, value); + return RContext.getRRuntimeASTAccess().createLanguageFromList(result, repType); + } + + @Specialization + @TruffleBoundary + protected Object doReplacementPairList(RPairList vector, Object[] positions, Object value, + @Cached("createForContainerTypes()") ReplaceVectorNode replace) { + return replace.execute(vector.toRList(), positions, value); + } + + protected static GenericVectorReplaceNode createGeneric() { + return new GenericVectorReplaceNode(); + } + + @Specialization(replaces = "doReplaceCached", guards = "!isForeignObject(vector)") + @TruffleBoundary + protected Object doReplaceDefaultGeneric(RAbstractVector vector, Object[] positions, Object value, // + @Cached("createGeneric()") GenericVectorReplaceNode generic) { + if (vector instanceof RAbstractListVector && isRecursiveSubscript(vector, positions)) { + return generic.getRecursive(this, vector, positions).apply(vector, positions, value); + } else { + return generic.get(this, vector, positions, value).apply(vector, positions, value); + } + } + + protected static final class GenericVectorReplaceNode extends TruffleBoundaryNode { + + @Child private RecursiveReplaceSubscriptNode cachedRecursive; + @Child private CachedReplaceVectorNode cached; + + private RecursiveReplaceSubscriptNode getRecursive(ReplaceVectorNode node, Object vector, Object[] positions) { + CompilerAsserts.neverPartOfCompilation(); + if (cachedRecursive == null || !cachedRecursive.isSupported(vector, positions)) { + cachedRecursive = insert(node.createRecursiveCache(vector, positions)); + } + return cachedRecursive; + } + + private CachedReplaceVectorNode get(ReplaceVectorNode node, RAbstractVector vector, Object[] positions, Object value) { + CompilerAsserts.neverPartOfCompilation(); + if (cached == null || !cached.isSupported(vector, positions, value)) { + cached = insert(node.createDefaultCached(vector, positions, value)); + } + return cached; + } } - protected R2Foreign createR2Foreign() { - return R2ForeignNodeGen.create(); + protected FirstStringNode createFirstString() { + return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access."); } @Specialization(guards = {"isForeignObject(object)", "positions.length == cachedLength"}) @@ -109,7 +281,7 @@ public abstract class ReplaceVectorNode extends RBaseNode { @SuppressWarnings("unused") @Cached("positions.length") int cachedLength, @Cached("create()") CastStringNode castNode, @Cached("createFirstString()") FirstStringNode firstString, - @Cached("createR2Foreign()") R2Foreign r2Foreign) { + @Cached("create()") R2Foreign r2Foreign) { Object writtenValue = value; try { TruffleObject result = object; @@ -163,65 +335,10 @@ public abstract class ReplaceVectorNode extends RBaseNode { return JavaInterop.toJavaClass(obj); } - @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(vector, positions)"}) - protected Object doRecursive(RAbstractListVector vector, Object[] positions, Object value, // - @Cached("createRecursiveCache(vector, positions)") RecursiveReplaceSubscriptNode cached) { - return cached.apply(vector, positions, value); - } - - protected RecursiveReplaceSubscriptNode createRecursiveCache(Object vector, Object[] positions) { - if (isRecursiveSubscript(vector, positions)) { - return RecursiveReplaceSubscriptNode.create((RAbstractListVector) vector, positions[0]); - } - return null; - } - - private boolean isRecursiveSubscript(Object vector, Object[] positions) { - return !recursive && !ignoreRecursive && mode.isSubscript() && vector instanceof RAbstractListVector && positions.length == 1; - } - - @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(vector, positions, value)"}) - protected Object doReplaceCached(Object vector, Object[] positions, Object value, // - @Cached("createDefaultCached(getThis(), vector, positions, value)") CachedReplaceVectorNode cached) { - assert !isRecursiveSubscript(vector, positions); - return cached.apply(vector, positions, value); - } - - protected static CachedReplaceVectorNode createDefaultCached(ReplaceVectorNode node, Object vector, Object[] positions, Object value) { - return new CachedReplaceVectorNode(node.mode, (RTypedValue) vector, positions, value.getClass(), RRuntime.isForeignObject(value) ? RType.TruffleObject : ((RTypedValue) value).getRType(), true, - node.recursive, node.ignoreRecursive, CachedReplaceVectorNode.isValueLengthGreaterThanOne(value)); - } - - public ElementAccessMode getMode() { - return mode; - } - - @Specialization(replaces = "doReplaceCached") - @TruffleBoundary - protected Object doReplaceDefaultGeneric(Object vector, Object[] positions, Object value, // - @Cached("new(createDefaultCached(getThis(), vector, positions, value))") GenericVectorReplaceNode generic) { - return generic.get(this, vector, positions, value).apply(vector, positions, value); - } - - // TODO hack until Truffle-DSL supports this. - protected ReplaceVectorNode getThis() { - return this; - } - - protected static final class GenericVectorReplaceNode extends TruffleBoundaryNode { - - @Child private CachedReplaceVectorNode cached; - - public GenericVectorReplaceNode(CachedReplaceVectorNode cachedOperation) { - this.cached = insert(cachedOperation); - } - - private CachedReplaceVectorNode get(ReplaceVectorNode node, Object vector, Object[] positions, Object value) { - CompilerAsserts.neverPartOfCompilation(); - if (!cached.isSupported(vector, positions, value)) { - cached = cached.replace(createDefaultCached(node, vector, positions, value)); - } - return cached; - } + @SuppressWarnings("unused") + @Fallback + protected Object access(Object object, Object[] positions, Object value) { + CompilerDirectives.transferToInterpreter(); + throw error(RError.Message.OBJECT_NOT_SUBSETTABLE, Predef.typeName().apply(object)); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java index aecab8b403bb429c8b83a54b1f5f561f191b12bd..28666c2bfe310626240eaa6f4f3086ec88b1b0ab 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/WriteIndexedVectorNode.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.nodes.access.vector; +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.api.nodes.Node; @@ -35,33 +36,84 @@ import com.oracle.truffle.r.nodes.function.opt.UpdateShareableChildValueNode; import com.oracle.truffle.r.nodes.profile.AlwaysOnBranchProfile; import com.oracle.truffle.r.nodes.profile.IntValueProfile; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; -import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; -import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RIntSequence; import com.oracle.truffle.r.runtime.data.RMissing; -import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.RScalarVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -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.RAbstractListBaseVector; 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.RandomIterator; import com.oracle.truffle.r.runtime.ops.na.NACheck; +abstract class WriteIndexedVectorNode extends Node { + + private final RType vectorType; + private final int totalDimensions; + private final int dimensionIndex; + private final boolean positionAppliesToRight; + private final boolean skipNA; + private final boolean isReplace; + + private final ConditionProfile completeVectorProfile = ConditionProfile.createBinaryProfile(); + + protected WriteIndexedVectorNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean isReplace) { + this.vectorType = vectorType; + this.totalDimensions = totalDimensions; + this.dimensionIndex = dimensionIndex; + this.positionAppliesToRight = positionAppliesToRight; + this.skipNA = skipNA; + this.isReplace = isReplace; + } + + public static WriteIndexedVectorNode create(RType vectorType, int totalDimensions, boolean positionAppliesToValue, boolean skipNA, boolean isReplace) { + return WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, totalDimensions - 1, positionAppliesToValue, skipNA, isReplace); + } + + protected abstract void execute(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions); + + protected WriteIndexedVectorAccessNode createWrite() { + return WriteIndexedVectorAccessNodeGen.create(vectorType, totalDimensions, dimensionIndex, positionAppliesToRight, skipNA, isReplace); + } + + @Specialization(guards = {"leftAccess.supports(left)", "rightAccess.supports(right)"}) + protected void write(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions, + @Cached("left.access()") VectorAccess leftAccess, + @Cached("right.access()") VectorAccess rightAccess, + @Cached("createWrite()") WriteIndexedVectorAccessNode write) { + try (RandomIterator leftIter = leftAccess.randomAccess(left); RandomIterator rightIter = rightAccess.randomAccess(right)) { + write.apply(leftIter, leftAccess, positions, rightIter, rightAccess, right, positionTargetDimensions); + + if (completeVectorProfile.profile(left.isComplete())) { + if (!(leftAccess.na.neverSeenNA() && rightAccess.na.neverSeenNA())) { + left.setComplete(false); + } + } + } + } + + @Specialization(replaces = "write") + @TruffleBoundary + protected void writeGeneric(RAbstractVector left, Object[] positions, RAbstractContainer right, int[] positionTargetDimensions, + @Cached("createWrite()") WriteIndexedVectorAccessNode write) { + VectorAccess leftAccess = left.slowPathAccess(); + VectorAccess rightAccess = right.slowPathAccess(); + try (RandomIterator leftIter = leftAccess.randomAccess(left); RandomIterator rightIter = rightAccess.randomAccess(right)) { + write.apply(leftIter, leftAccess, positions, rightIter, rightAccess, right, positionTargetDimensions); + } + } +} + /** * Primitive indexed N-dimensional vector write node. It can be used for vector replaces and * extracts. The only difference is that replace indexes the left vector and extract indexes the * right vector. The index direction is indicated with the boolean flag * {@link #positionsApplyToRight}. */ -abstract class WriteIndexedVectorNode extends Node { +abstract class WriteIndexedVectorAccessNode extends Node { private final int dimensionIndex; private final int totalDimensions; @@ -84,57 +136,39 @@ abstract class WriteIndexedVectorNode extends Node { private final NACheck positionNACheck = NACheck.create(); private final ConditionProfile resetIndexProfile = ConditionProfile.createBinaryProfile(); - @Child private WriteIndexedScalarNode<RAbstractVector, Object> scalarNode; - @Child private WriteIndexedVectorNode innerVectorNode; + @Child private WriteIndexedVectorAccessNode innerVectorNode; + + @Child private UpdateShareableChildValueNode updateStateOfListElement; + @Child private ShareObjectNode shareObjectNode; - @SuppressWarnings("unchecked") - protected WriteIndexedVectorNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean setListElementAsObject, boolean isReplace) { - this.scalarNode = (WriteIndexedScalarNode<RAbstractVector, Object>) createIndexedAction(vectorType, setListElementAsObject, isReplace); + private final boolean isReplace; + private final RType vectorType; + + protected WriteIndexedVectorAccessNode(RType vectorType, int totalDimensions, int dimensionIndex, boolean positionAppliesToRight, boolean skipNA, boolean isReplace) { + this.vectorType = vectorType; this.dimensionIndex = dimensionIndex; this.totalDimensions = totalDimensions; this.positionsApplyToRight = positionAppliesToRight; this.skipNA = skipNA; + this.isReplace = isReplace; if (dimensionIndex > 0) { - innerVectorNode = WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, dimensionIndex - 1, positionAppliesToRight, skipNA, setListElementAsObject, isReplace); - } - } - - public static WriteIndexedVectorNode create(RType vectorType, int totalDimensions, boolean positionAppliesToValue, boolean skipNA, boolean setListElementAsObject, boolean isReplace) { - return WriteIndexedVectorNodeGen.create(vectorType, totalDimensions, totalDimensions - 1, positionAppliesToValue, skipNA, setListElementAsObject, isReplace); - } - - public NACheck getValueNACheck() { - return scalarNode.valueNACheck; - } - - public void enableValueNACheck(RAbstractContainer vector) { - getValueNACheck().enable(vector); - if (innerVectorNode != null) { - innerVectorNode.enableValueNACheck(vector); + innerVectorNode = WriteIndexedVectorAccessNodeGen.create(vectorType, totalDimensions, dimensionIndex - 1, positionAppliesToRight, skipNA, isReplace); } - } - - public boolean neverSeenNAInValue() { - if (getValueNACheck().neverSeenNA()) { - if (innerVectorNode == null || innerVectorNode.neverSeenNAInValue()) { - return true; + if (vectorType == RType.List || vectorType == RType.Expression) { + if (!isReplace) { + updateStateOfListElement = UpdateShareableChildValueNode.create(); + } else { + shareObjectNode = ShareObjectNode.create(); } } - return false; } - public final void apply(RAbstractVector left, int leftLength, - Object[] positions, Object right, int rightLength, int[] positionTargetDimensions) { - assert left.getLength() == leftLength; + public void apply(RandomIterator leftIter, VectorAccess leftAccess, Object[] positions, RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, + int[] positionTargetDimensions) { assert totalDimensions == positions.length : "totalDimensions must be constant per vector write node"; - Object leftStore = left.getInternalStore(); - Object rightStore = null; - if (right instanceof RAbstractContainer) { - RAbstractContainer rightContainer = (RAbstractContainer) right; - assert rightContainer.getLength() == rightLength; - rightStore = rightContainer.getInternalStore(); - } + int leftLength = leftAccess.getLength(leftIter); + int rightLength = rightAccess.getLength(rightIter); int initialPositionOffset; if (positionsApplyToRight) { @@ -151,17 +185,17 @@ abstract class WriteIndexedVectorNode extends Node { firstTargetDimension = dimensionValueProfile.profile(positionTargetDimensions[dimensionIndex]); } - applyImpl(left, leftStore, 0, leftLength, positionTargetDimensions, firstTargetDimension, + applyImpl(leftIter, leftAccess, 0, leftLength, positionTargetDimensions, firstTargetDimension, positions, initialPositionOffset, - right, rightStore, 0, rightLength, false); + rightIter, rightAccess, right, 0, rightLength, false); } private final ConditionProfile positionMatchesTargetDimensionsProfile = ConditionProfile.createBinaryProfile(); private int applyImpl(// - RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension, + RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension, Object[] positions, int positionOffset, - Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA) { + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA) { Object position = positionClassProfile.profile(positions[dimensionIndex]); @@ -172,9 +206,9 @@ abstract class WriteIndexedVectorNode extends Node { } else { newPositionOffset = positionOffsetProfile.profile(positionOffset / targetDimension); } - return execute(left, leftStore, leftBase, leftLength, targetDimensions, targetDimension, + return execute(leftIter, leftAccess, leftBase, leftLength, targetDimensions, targetDimension, positions, position, newPositionOffset, positionLength, - right, rightStore, rightBase, rightLength, parentNA); + rightIter, rightAccess, right, rightBase, rightLength, parentNA); } private int getPositionLength(Object position) { @@ -185,30 +219,30 @@ abstract class WriteIndexedVectorNode extends Node { } } - protected abstract int execute(RAbstractVector left, Object leftStore, int storeBase, int storeLength, Object targetDimensions, int targetDimension, + protected abstract int execute(RandomIterator leftIter, VectorAccess leftAccess, int storeBase, int storeLength, Object targetDimensions, int targetDimension, Object[] positions, Object position, int positionOffset, int positionLength, - Object right, Object rightStore, int valueBase, int valueLength, boolean parentNA); + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int valueBase, int valueLength, boolean parentNA); @Specialization - protected int doMissing(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension, + protected int doMissing(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension, Object[] positions, @SuppressWarnings("unused") RMissing position, int positionOffset, @SuppressWarnings("unused") int positionLength, - RAbstractContainer right, Object rightStore, int rightBase, int rightLength, boolean parentNA, + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA, @Cached("createCountingProfile()") LoopConditionProfile profile) { int rightIndex = rightBase; profile.profileCounted(targetDimension); for (int positionValue = 0; profile.inject(positionValue < targetDimension); positionValue += 1) { rightIndex = applyInner(// - left, leftStore, leftBase, leftLength, targetDimensions, + leftIter, leftAccess, leftBase, leftLength, targetDimensions, positions, positionOffset, positionValue, - right, rightStore, rightLength, rightIndex, parentNA); + rightIter, rightAccess, right, rightLength, rightIndex, parentNA); } return rightIndex; } @Specialization - protected int doLogicalPosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, int targetDimension, + protected int doLogicalPosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, int targetDimension, Object[] positions, RAbstractLogicalVector position, int positionOffset, int positionLength, - Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA, + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA, @Cached("create()") BranchProfile wasTrue, @Cached("create()") AlwaysOnBranchProfile outOfBounds, @Cached("createCountingProfile()") LoopConditionProfile profile, @@ -235,9 +269,9 @@ abstract class WriteIndexedVectorNode extends Node { isNA = true; } rightIndex = applyInner(// - left, leftStore, leftBase, leftLength, targetDimensions, + leftIter, leftAccess, leftBase, leftLength, targetDimensions, positions, positionOffset, i, - right, rightStore, rightLength, rightIndex, isNA || parentNA); + rightIter, rightAccess, right, rightLength, rightIndex, isNA || parentNA); } positionIndex = Utils.incMod(positionIndex, positionLength, incModProfile); } @@ -251,9 +285,9 @@ abstract class WriteIndexedVectorNode extends Node { * @throws SlowPathException */ @Specialization(rewriteOn = SlowPathException.class) - protected int doIntegerSequencePosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension, + protected int doIntegerSequencePosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension, Object[] positions, RIntSequence position, int positionOffset, int positionLength, - Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA, + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA, @Cached("create()") IntValueProfile startProfile, @Cached("create()") IntValueProfile strideProfile, @Cached("createBinaryProfile()") ConditionProfile conditionProfile, @@ -272,27 +306,22 @@ abstract class WriteIndexedVectorNode extends Node { profile.profileCounted(positionLength); for (int positionValue = start; profile.inject(ascending ? positionValue < end : positionValue > end); positionValue += stride) { rightIndex = applyInner(// - left, leftStore, leftBase, leftLength, targetDimensions, + leftIter, leftAccess, leftBase, leftLength, targetDimensions, positions, positionOffset, positionValue, - right, rightStore, rightLength, rightIndex, parentNA); + rightIter, rightAccess, right, rightLength, rightIndex, parentNA); } return rightIndex; } /** * Integer vectors iterate over the number of positions because we assume that the number of - * positions in an integer vector is significantly lower than the number of elements in the - * store. This might not be always true and could benefit from more investigation. - */ - /** - * Integer vectors iterate over the number of positions because we assume that the number of - * positions in an integer vector is significantly lower than the number of elements in the - * store. This might not be always true and could benefit from more investigation. + * positions in an integer vector is significantly lower than the number of elements. This might + * not be always true and could benefit from more investigation. */ @Specialization(replaces = "doIntegerSequencePosition") - protected int doIntegerPosition(RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension, + protected int doIntegerPosition(RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, @SuppressWarnings("unused") int targetDimension, Object[] positions, RAbstractIntVector position, int positionOffset, int positionLength, - Object right, Object rightStore, int rightBase, int rightLength, boolean parentNA, + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightBase, int rightLength, boolean parentNA, @Cached("createCountingProfile()") LoopConditionProfile lengthProfile) { positionNACheck.enable(position); int rightIndex = rightBase; @@ -307,17 +336,17 @@ abstract class WriteIndexedVectorNode extends Node { } } rightIndex = applyInner(// - left, leftStore, leftBase, leftLength, targetDimensions, + leftIter, leftAccess, leftBase, leftLength, targetDimensions, positions, positionOffset, positionValue - 1, - right, rightStore, rightLength, rightIndex, isNA || parentNA); + rightIter, rightAccess, right, rightLength, rightIndex, isNA || parentNA); } return rightIndex; } private int applyInner(// - RAbstractVector left, Object leftStore, int leftBase, int leftLength, Object targetDimensions, + RandomIterator leftIter, VectorAccess leftAccess, int leftBase, int leftLength, Object targetDimensions, Object[] positions, int positionOffset, int positionValue, - Object right, Object rightStore, int rightLength, int actionIndex, boolean isNA) { + RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int rightLength, int actionIndex, boolean isNA) { int newTargetIndex = leftBase + positionValue * positionOffset; if (dimensionIndex == 0) { // for-loops leaf for innermost dimension @@ -334,9 +363,15 @@ abstract class WriteIndexedVectorNode extends Node { } if (isNA) { - scalarNode.applyNA(left, leftStore, actionLeftIndex); + leftAccess.setNA(leftIter, actionLeftIndex); + leftAccess.na.seenNA(); } else { - scalarNode.apply(left, leftStore, actionLeftIndex, right, rightStore, actionRightIndex); + if (vectorType == RType.List || vectorType == RType.Expression) { + setListElement(leftIter, leftAccess, rightIter, rightAccess, right, actionLeftIndex, actionRightIndex); + } else { + leftAccess.setFromSameType(leftIter, actionLeftIndex, rightAccess, rightIter, actionRightIndex); + } + rightAccess.isNA(rightIter, actionRightIndex); } if (resetIndexProfile.profile((actionIndex + 1) == (positionsApplyToRight ? leftLength : rightLength))) { @@ -347,189 +382,24 @@ abstract class WriteIndexedVectorNode extends Node { // generate another for-loop for other dimensions int nextTargetDimension = innerVectorNode.dimensionValueProfile.profile(((int[]) targetDimensions)[innerVectorNode.dimensionIndex]); return innerVectorNode.applyImpl(// - left, leftStore, newTargetIndex, leftLength, targetDimensions, nextTargetDimension, + leftIter, leftAccess, newTargetIndex, leftLength, targetDimensions, nextTargetDimension, positions, positionOffset, - right, rightStore, actionIndex, rightLength, isNA); - } - } - - private static WriteIndexedScalarNode<? extends RAbstractVector, ? extends Object> createIndexedAction(RType type, boolean setListElementAsObject, boolean isReplace) { - switch (type) { - case Logical: - return new WriteLogicalAction(); - case Integer: - return new WriteIntegerAction(); - case Double: - return new WriteDoubleAction(); - case Complex: - return new WriteComplexAction(); - case Character: - return new WriteCharacterAction(); - case Raw: - return new WriteRawAction(); - case Language: - case Expression: - case PairList: - case List: - return new WriteListAction(setListElementAsObject, isReplace); - default: - throw RInternalError.shouldNotReachHere("WriteIndexedScalarNode for " + type); - } - } - - private abstract static class WriteIndexedScalarNode<A extends RAbstractVector, V extends Object> extends Node { - - final NACheck valueNACheck = NACheck.create(); - - abstract void apply(A leftAccess, Object leftStore, int leftIndex, V rightAccess, Object rightStore, int rightIndex); - - abstract void applyNA(A leftAccess, Object leftStore, int leftIndex); - - } - - private static final class WriteLogicalAction extends WriteIndexedScalarNode<RAbstractLogicalVector, RAbstractLogicalVector> { - - @Override - void apply(RAbstractLogicalVector leftAccess, Object leftStore, int leftIndex, RAbstractLogicalVector rightAccess, Object rightStore, int rightIndex) { - byte value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractLogicalVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RRuntime.LOGICAL_NA); - valueNACheck.seenNA(); - } - } - - private static final class WriteIntegerAction extends WriteIndexedScalarNode<RAbstractIntVector, RAbstractIntVector> { - - @Override - void apply(RAbstractIntVector leftAccess, Object leftStore, int leftIndex, RAbstractIntVector rightAccess, Object rightStore, int rightIndex) { - int value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractIntVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RRuntime.INT_NA); - valueNACheck.seenNA(); - } - } - - private static final class WriteDoubleAction extends WriteIndexedScalarNode<RAbstractDoubleVector, RAbstractDoubleVector> { - - @Override - void apply(RAbstractDoubleVector leftAccess, Object leftStore, int leftIndex, RAbstractDoubleVector rightAccess, Object rightStore, int rightIndex) { - double value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractDoubleVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RRuntime.DOUBLE_NA); - valueNACheck.seenNA(); - } - } - - private static final class WriteComplexAction extends WriteIndexedScalarNode<RAbstractComplexVector, RAbstractComplexVector> { - - @Override - void apply(RAbstractComplexVector leftAccess, Object leftStore, int leftIndex, RAbstractComplexVector rightAccess, Object rightStore, int rightIndex) { - RComplex value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractComplexVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RComplex.createNA()); - valueNACheck.seenNA(); + rightIter, rightAccess, right, actionIndex, rightLength, isNA); } } - private static final class WriteCharacterAction extends WriteIndexedScalarNode<RAbstractStringVector, RAbstractStringVector> { - - @Override - void apply(RAbstractStringVector leftAccess, Object leftStore, int leftIndex, RAbstractStringVector rightAccess, Object rightStore, int rightIndex) { - String value = rightAccess.getDataAt(rightStore, rightIndex); - leftAccess.setDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractStringVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RRuntime.STRING_NA); - valueNACheck.seenNA(); - } - } - - private static final class WriteRawAction extends WriteIndexedScalarNode<RAbstractRawVector, RAbstractRawVector> { - - @Override - void apply(RAbstractRawVector leftAccess, Object leftStore, int leftIndex, RAbstractRawVector rightAccess, Object rightStore, int rightIndex) { - byte value = rightAccess.getRawDataAt(rightStore, rightIndex); - leftAccess.setRawDataAt(leftStore, leftIndex, value); - valueNACheck.check(value); - } - - @Override - void applyNA(RAbstractRawVector leftAccess, Object leftStore, int leftIndex) { - // nothing to do - } - } - - private static final class WriteListAction extends WriteIndexedScalarNode<RAbstractListBaseVector, Object> { - - private final boolean setListElementAsObject; - private final boolean isReplace; - @Child private UpdateShareableChildValueNode updateStateOfListElement; - @Child private ShareObjectNode shareObjectNode; - - WriteListAction(boolean setListElementAsObject, boolean isReplace) { - this.setListElementAsObject = setListElementAsObject; - this.isReplace = isReplace; - if (!isReplace) { - updateStateOfListElement = UpdateShareableChildValueNode.create(); - } else { - shareObjectNode = ShareObjectNode.create(); + private void setListElement(RandomIterator leftIter, VectorAccess leftAccess, RandomIterator rightIter, VectorAccess rightAccess, RAbstractContainer right, int leftIndex, int rightIndex) { + Object rightValue = rightAccess.getListElement(rightIter, rightIndex); + if (isReplace) { + // we are replacing within the same list + if (leftAccess.getListElement(leftIter, leftIndex) != rightValue) { + shareObjectNode.execute(rightValue); } + } else { + // we are writing into a list data that are being read from possibly another list + updateStateOfListElement.execute(right, rightValue); } - @Override - void apply(RAbstractListBaseVector leftAccess, Object leftStore, int leftIndex, Object rightAccess, Object rightStore, int rightIndex) { - Object rightValue; - if (setListElementAsObject) { - rightValue = rightAccess; - // unbox scalar vectors - if (rightValue instanceof RScalarVector) { - rightValue = ((RScalarVector) rightValue).getDataAtAsObject(rightStore, 0); - } - } else { - rightValue = ((RAbstractContainer) rightAccess).getDataAtAsObject(rightStore, rightIndex); - } - - if (isReplace) { - // we are replacing within the same list - if (leftAccess.getDataAtAsObject(leftStore, leftIndex) != rightValue) { - shareObjectNode.execute(rightValue); - } - } else { - // we are writing into a list data that are being read from possibly another list - updateStateOfListElement.execute(rightAccess, rightValue); - } - - leftAccess.setDataAt(leftStore, leftIndex, rightValue); - valueNACheck.checkListElement(rightValue); - } - - @Override - void applyNA(RAbstractListBaseVector leftAccess, Object leftStore, int leftIndex) { - leftAccess.setDataAt(leftStore, leftIndex, RNull.instance); - valueNACheck.seenNA(); - } + leftAccess.setListElement(leftIter, leftIndex, rightValue); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java index 6af290e8b548d3f283e78459085726d2507c3bb6..96d5b62296049ad4bc60fde9876f0c20d9535a03 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryArithmeticNode.java @@ -87,29 +87,27 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 { } @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(left, right)"}) - protected Object doNumericVectorCached(Object left, Object right, + protected Object doNumericVectorCached(RAbstractVector left, RAbstractVector right, @Cached("createFastCached(left, right)") BinaryMapNode cached) { return cached.apply(left, right); } @Specialization(replaces = "doNumericVectorCached", guards = {"isNumericVector(left)", "isNumericVector(right)"}) @TruffleBoundary - protected Object doNumericVectorGeneric(Object left, Object right, + protected Object doNumericVectorGeneric(RAbstractVector left, RAbstractVector right, @Cached("binary.createOperation()") BinaryArithmetic arithmetic, - @Cached("new(createCached(arithmetic, left, right))") GenericNumericVectorNode generic) { - RAbstractVector leftVector = (RAbstractVector) left; - RAbstractVector rightVector = (RAbstractVector) right; - return generic.get(arithmetic, leftVector, rightVector).apply(leftVector, rightVector); + @Cached("createGeneric()") GenericNumericVectorNode generic) { + return generic.get(arithmetic, left, right).apply(left, right); } - protected BinaryMapNode createFastCached(Object left, Object right) { + protected BinaryMapNode createFastCached(RAbstractVector left, RAbstractVector right) { if (isNumericVector(left) && isNumericVector(right)) { - return createCached(binary.createOperation(), left, right); + return createCached(binary.createOperation(), left, right, false); } return null; } - protected static boolean isNumericVector(Object value) { + protected static boolean isNumericVector(RAbstractVector value) { return value instanceof RAbstractIntVector || value instanceof RAbstractDoubleVector || value instanceof RAbstractComplexVector || value instanceof RAbstractLogicalVector; } @@ -133,19 +131,19 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 { } @Specialization(guards = {"isNumericVector(right)"}) - protected Object doLeftNull(@SuppressWarnings("unused") RNull left, Object right, + protected Object doLeftNull(@SuppressWarnings("unused") RNull left, RAbstractVector right, @Cached("createClassProfile()") ValueProfile classProfile) { - RType rType = ((RAbstractVector) classProfile.profile(right)).getRType(); - if (rType == RType.Complex) { + RType type = classProfile.profile(right).getRType(); + if (type == RType.Complex) { return RDataFactory.createEmptyComplexVector(); } else { - if (rType == RType.Integer || rType == RType.Logical) { + if (type == RType.Integer || type == RType.Logical) { if (operation instanceof BinaryArithmetic.Div || operation instanceof BinaryArithmetic.Pow) { return RType.Double.getEmpty(); } else { return RType.Integer.getEmpty(); } - } else if (rType == RType.Double) { + } else if (type == RType.Double) { return RType.Double.getEmpty(); } else { throw error(Message.NON_NUMERIC_BINARY); @@ -154,7 +152,7 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 { } @Specialization(guards = {"isNumericVector(left)"}) - protected Object doRightNull(Object left, RNull right, + protected Object doRightNull(RAbstractVector left, RNull right, @Cached("createClassProfile()") ValueProfile classProfile) { return doLeftNull(right, left, classProfile); } @@ -164,7 +162,7 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 { throw error(Message.NON_NUMERIC_BINARY); } - protected static BinaryMapNode createCached(BinaryArithmetic innerArithmetic, Object left, Object right) { + protected static BinaryMapNode createCached(BinaryArithmetic innerArithmetic, Object left, Object right, boolean isGeneric) { RAbstractVector leftVector = (RAbstractVector) left; RAbstractVector rightVector = (RAbstractVector) right; @@ -174,22 +172,22 @@ public abstract class BinaryArithmeticNode extends RBuiltinNode.Arg2 { resultType = RType.Double; } - return BinaryMapNode.create(new BinaryMapArithmeticFunctionNode(innerArithmetic), leftVector, rightVector, argumentType, resultType, true); + return BinaryMapNode.create(new BinaryMapArithmeticFunctionNode(innerArithmetic), leftVector, rightVector, argumentType, resultType, true, isGeneric); + } + + protected static GenericNumericVectorNode createGeneric() { + return new GenericNumericVectorNode(); } protected static final class GenericNumericVectorNode extends TruffleBoundaryNode { @Child private BinaryMapNode cached; - public GenericNumericVectorNode(BinaryMapNode cachedOperation) { - this.cached = insert(cachedOperation); - } - public BinaryMapNode get(BinaryArithmetic arithmetic, RAbstractVector left, RAbstractVector right) { CompilerAsserts.neverPartOfCompilation(); BinaryMapNode map = cached; - if (!map.isSupported(left, right)) { - cached = map = map.replace(createCached(arithmetic, left, right)); + if (map == null || !map.isSupported(left, right)) { + cached = map = insert(createCached(arithmetic, left, right, true)); } return map; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java index bae281a74708b2017a5659fe5a48430fa37bf444..b367673e3376d89d14d59cd085f5ee232c0b4cbd 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanNode.java @@ -104,24 +104,22 @@ public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 { } @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(left, right)"}) - protected Object doNumericVectorCached(Object left, Object right, + protected Object doNumericVectorCached(RAbstractVector left, RAbstractVector right, @Cached("createFastCached(left, right)") BinaryMapNode cached) { return cached.apply(left, right); } @Specialization(replaces = "doNumericVectorCached", guards = "isSupported(left, right)") @TruffleBoundary - protected Object doNumericVectorGeneric(Object left, Object right, + protected Object doNumericVectorGeneric(RAbstractVector left, RAbstractVector right, @Cached("factory.createOperation()") BooleanOperation operation, - @Cached("new(createCached(operation, left, right))") GenericNumericVectorNode generic) { - RAbstractVector leftVector = (RAbstractVector) left; - RAbstractVector rightVector = (RAbstractVector) right; - return generic.get(operation, leftVector, rightVector).apply(leftVector, rightVector); + @Cached("createGeneric()") GenericNumericVectorNode generic) { + return generic.get(operation, left, right).apply(left, right); } protected BinaryMapNode createFastCached(Object left, Object right) { if (isSupported(left, right)) { - return createCached(factory.createOperation(), left, right); + return createCached(factory.createOperation(), left, right, false); } return null; } @@ -243,7 +241,7 @@ public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 { throw error(Message.OPERATIONS_NUMERIC_LOGICAL_COMPLEX); } - protected static BinaryMapNode createCached(BooleanOperation operation, Object left, Object right) { + protected static BinaryMapNode createCached(BooleanOperation operation, Object left, Object right, boolean isGeneric) { RAbstractVector leftVector = (RAbstractVector) left; RAbstractVector rightVector = (RAbstractVector) right; @@ -255,23 +253,24 @@ public abstract class BinaryBooleanNode extends RBuiltinNode.Arg2 { resultType = RType.Logical; } - return BinaryMapNode.create(new BinaryMapBooleanFunctionNode(operation), leftVector, rightVector, argumentType, resultType, false); + return BinaryMapNode.create(new BinaryMapBooleanFunctionNode(operation), leftVector, rightVector, argumentType, resultType, false, isGeneric); + } + + protected static GenericNumericVectorNode createGeneric() { + return new GenericNumericVectorNode(); } protected static final class GenericNumericVectorNode extends TruffleBoundaryNode { @Child private BinaryMapNode cached; - public GenericNumericVectorNode(BinaryMapNode cachedOperation) { - this.cached = insert(cachedOperation); - } - private BinaryMapNode get(BooleanOperation arithmetic, RAbstractVector left, RAbstractVector right) { CompilerAsserts.neverPartOfCompilation(); - if (!cached.isSupported(left, right)) { - cached = cached.replace(createCached(arithmetic, left, right)); + BinaryMapNode map = cached; + if (map == null || !map.isSupported(left, right)) { + cached = map = insert(createCached(arithmetic, left, right, true)); } - return cached; + return map; } } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java index e0c252dfd5387ebc560c2f338682add035352804..037b7b409d29b3cb39e93ba4cd6dba9da5156f9f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/PipelineToCastNode.java @@ -299,48 +299,49 @@ public final class PipelineToCastNode { @Override public ArgumentFilter<?, ?> visit(RTypeFilter<?> filter, ArgumentFilter<?, ?> previous) { - if (filter.getType() == RType.Integer) { - return new ArgumentFilter<Object, Object>() { - private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); - - @Override - public boolean test(Object x) { - return profile.profile(x instanceof Integer) || x instanceof RAbstractIntVector; - } - }; - } else if (filter.getType() == RType.Double) { - return new ArgumentFilter<Object, Object>() { - private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); - - @Override - public boolean test(Object x) { - return profile.profile(x instanceof Double) || x instanceof RAbstractDoubleVector; - } - }; - } else if (filter.getType() == RType.Logical) { - return new ArgumentFilter<Object, Object>() { - private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); - - @Override - public boolean test(Object x) { - return profile.profile(x instanceof Byte) || x instanceof RAbstractLogicalVector; - } - }; - } else if (filter.getType() == RType.Complex) { - return x -> x instanceof RAbstractComplexVector; - } else if (filter.getType() == RType.Character) { - return new ArgumentFilter<Object, Object>() { - private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); - - @Override - public boolean test(Object x) { - return profile.profile(x instanceof String) || x instanceof RAbstractStringVector; - } - }; - } else if (filter.getType() == RType.Raw) { - return x -> x instanceof RAbstractRawVector; - } else { - throw RInternalError.unimplemented("TODO: more types here"); + switch (filter.getType()) { + case Integer: + return new ArgumentFilter<Object, Object>() { + private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); + + @Override + public boolean test(Object x) { + return profile.profile(x instanceof Integer) || x instanceof RAbstractIntVector; + } + }; + case Double: + return new ArgumentFilter<Object, Object>() { + private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); + + @Override + public boolean test(Object x) { + return profile.profile(x instanceof Double) || x instanceof RAbstractDoubleVector; + } + }; + case Logical: + return new ArgumentFilter<Object, Object>() { + private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); + + @Override + public boolean test(Object x) { + return profile.profile(x instanceof Byte) || x instanceof RAbstractLogicalVector; + } + }; + case Complex: + return x -> x instanceof RAbstractComplexVector; + case Character: + return new ArgumentFilter<Object, Object>() { + private final ConditionProfile profile = ConditionProfile.createBinaryProfile(); + + @Override + public boolean test(Object x) { + return profile.profile(x instanceof String) || x instanceof RAbstractStringVector; + } + }; + case Raw: + return x -> x instanceof RAbstractRawVector; + default: + throw RInternalError.unimplemented("type " + filter.getType()); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java index 8498a61289235f2e0c4de993b38c06492030a46f..7a3866e37c07060d7d91c0874338fefd8e6f67b0 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/control/ForNode.java @@ -200,11 +200,11 @@ public abstract class ForNode extends AbstractLoopNode implements RSyntaxNode, R return createLoopNode(new ForIndexRepeatingNode(this, var.getIdentifier(), RASTUtils.cloneNode(body), indexName, lengthName, rangeName)); } - private LoopNode createLoopNode(AbstractRepeatingNode n) { + private static LoopNode createLoopNode(AbstractRepeatingNode n) { return Truffle.getRuntime().createLoopNode(n); } - private TruffleObject getIterator(TruffleObject obj, Node readNode, Node executeNode) { + private static TruffleObject getIterator(TruffleObject obj, Node readNode, Node executeNode) { assert ForeignArray2R.isJavaIterable(obj); try { TruffleObject itFun = (TruffleObject) ForeignAccess.sendRead(readNode, obj, "iterator"); @@ -214,7 +214,7 @@ public abstract class ForNode extends AbstractLoopNode implements RSyntaxNode, R } } - private int getKeysLength(TruffleObject keys, Node sizeNode) { + private static int getKeysLength(TruffleObject keys, Node sizeNode) { try { return (int) ForeignAccess.sendGetSize(sizeNode, keys); } catch (UnsupportedMessageException ex) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java index 74d41d8ec674bbe75c785baf3bcf2bfe096fffd4..243858790910424768d6deb86ac0510659900f49 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/PromiseHelperNode.java @@ -58,9 +58,9 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode; * Holds {@link RPromise}-related functionality that cannot be implemented in * "com.oracle.truffle.r.runtime.data" due to package import restrictions. */ -public class PromiseHelperNode extends RBaseNode { +public final class PromiseHelperNode extends RBaseNode { - public static class PromiseCheckHelperNode extends RBaseNode { + public static final class PromiseCheckHelperNode extends RBaseNode { @Child private PromiseHelperNode promiseHelper; @@ -81,7 +81,7 @@ public class PromiseHelperNode extends RBaseNode { } } - public static class PromiseDeoptimizeFrameNode extends RBaseNode { + public static final class PromiseDeoptimizeFrameNode extends RBaseNode { private final BranchProfile deoptimizeProfile = BranchProfile.create(); /** diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java index dd6ba6f6a16f2c99731e4d0a9f662530dc94afbb..2d5361356d9f10c047f8789210694473da303f1d 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/AsS4.java @@ -54,7 +54,7 @@ public abstract class AsS4 extends Node { if (complete != 0) { if (getS4DataSlot == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); - getS4DataSlot = insert(GetS4DataSlotNodeGen.create(RType.Any)); + getS4DataSlot = insert(GetS4DataSlot.create(RType.Any)); } RTypedValue value = getS4DataSlot.executeObject(obj); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java index 6d2ca9ae16f77f59d89a0f82797bd97cd367ec40..37827a9f33541330ddb84de42102c0d30d1d285c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/GetS4DataSlot.java @@ -13,7 +13,6 @@ package com.oracle.truffle.r.nodes.objects; import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.BranchProfile; @@ -32,9 +31,7 @@ import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RTypedValue; // transcribed from src/main/attrib.c -public abstract class GetS4DataSlot extends Node { - - public abstract RTypedValue executeObject(RAttributable attObj); +public final class GetS4DataSlot extends Node { @Child private GetFixedAttributeNode s3ClassAttrAccess; @Child private RemoveFixedAttributeNode s3ClassAttrRemove; @@ -48,12 +45,19 @@ public abstract class GetS4DataSlot extends Node { private final RType type; - protected GetS4DataSlot(RType type) { + private GetS4DataSlot(RType type) { this.type = type; } - @Specialization - protected RTypedValue doNewObject(RAttributable attrObj) { + public static GetS4DataSlot create(RType type) { + return new GetS4DataSlot(type); + } + + public static GetS4DataSlot createEnvironment() { + return new GetS4DataSlot(RType.Environment); + } + + public RTypedValue executeObject(RAttributable attrObj) { RAttributable obj = attrObj; Object value = null; if (!(obj instanceof RS4Object) || type == RType.S4Object) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java index a77f74f63d9ab98891b5b20991a0594958294612..51200dd1cf40613c23a7d68ef8b432764d1a3eec 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/BinaryMapNode.java @@ -22,8 +22,8 @@ */ package com.oracle.truffle.r.nodes.primitive; +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.LoopConditionProfile; @@ -31,7 +31,6 @@ import com.oracle.truffle.r.nodes.attributes.CopyAttributesNode; import com.oracle.truffle.r.nodes.attributes.CopyAttributesNodeGen; import com.oracle.truffle.r.nodes.attributes.HasFixedAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; -import com.oracle.truffle.r.nodes.primitive.BinaryMapNodeFactory.VectorMapBinaryInternalNodeGen; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; @@ -42,110 +41,229 @@ import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RScalarVector; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RVector; -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.GetDataStore; -import com.oracle.truffle.r.runtime.data.nodes.SetDataAt; -import com.oracle.truffle.r.runtime.data.nodes.VectorIterator; +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; import com.oracle.truffle.r.runtime.nodes.RBaseNode; -/** - * Implements a binary map operation that maps two vectors into a single result vector of the - * maximum size of both vectors. Vectors with smaller length are repeated. The actual implementation - * is provided using a {@link BinaryMapFunctionNode}. - * - * The implementation tries to share input vectors if they are implementing {@link RShareable}. - */ -public final class BinaryMapNode extends RBaseNode { +final class BinaryMapScalarNode extends BinaryMapNode { + + @Child private VectorAccess leftAccess; + @Child private VectorAccess rightAccess; + + BinaryMapScalarNode(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType) { + super(function, left, right, argumentType, resultType); + this.leftAccess = left.access(); + this.rightAccess = right.access(); + } + + @Override + public boolean isSupported(RAbstractVector left, RAbstractVector right) { + return leftAccess.supports(left) && rightAccess.supports(right); + } + + @Override + public Object apply(RAbstractVector originalLeft, RAbstractVector originalRight) { + assert isSupported(originalLeft, originalRight); + RAbstractVector left = leftClass.cast(originalLeft); + RAbstractVector right = rightClass.cast(originalRight); + try (RandomIterator leftIter = leftAccess.randomAccess(left); RandomIterator rightIter = rightAccess.randomAccess(right)) { + + assert left != null; + assert right != null; + function.enable(left, right); + assert leftAccess.getLength(leftIter) == 1; + assert rightAccess.getLength(rightIter) == 1; + + switch (argumentType) { + case Raw: + byte leftValueRaw = leftAccess.getRaw(leftIter, 0); + byte rightValueRaw = rightAccess.getRaw(rightIter, 0); + switch (resultType) { + case Raw: + return RRaw.valueOf(function.applyRaw(leftValueRaw, rightValueRaw)); + case Logical: + return function.applyLogical(RRuntime.raw2int(leftValueRaw), RRuntime.raw2int(rightValueRaw)); + default: + throw RInternalError.shouldNotReachHere(); + } + case Logical: + byte leftValueLogical = leftAccess.getLogical(leftIter, 0); + byte rightValueLogical = rightAccess.getLogical(rightIter, 0); + return function.applyLogical(leftValueLogical, rightValueLogical); + case Integer: + int leftValueInt = leftAccess.getInt(leftIter, 0); + int rightValueInt = rightAccess.getInt(rightIter, 0); + switch (resultType) { + case Logical: + return function.applyLogical(leftValueInt, rightValueInt); + case Integer: + return function.applyInteger(leftValueInt, rightValueInt); + case Double: + return function.applyDouble(leftValueInt, rightValueInt); + default: + throw RInternalError.shouldNotReachHere(); + } + case Double: + double leftValueDouble = leftAccess.getDouble(leftIter, 0); + double rightValueDouble = rightAccess.getDouble(rightIter, 0); + switch (resultType) { + case Logical: + return function.applyLogical(leftValueDouble, rightValueDouble); + case Double: + return function.applyDouble(leftValueDouble, rightValueDouble); + default: + throw RInternalError.shouldNotReachHere(); + } + case Complex: + RComplex leftValueComplex = leftAccess.getComplex(leftIter, 0); + RComplex rightValueComplex = rightAccess.getComplex(rightIter, 0); + switch (resultType) { + case Logical: + return function.applyLogical(leftValueComplex, rightValueComplex); + case Complex: + return function.applyComplex(leftValueComplex, rightValueComplex); + default: + throw RInternalError.shouldNotReachHere(); + } + case Character: + String leftValueString = leftAccess.getString(leftIter, 0); + String rightValueString = rightAccess.getString(rightIter, 0); + switch (resultType) { + case Logical: + return function.applyLogical(leftValueString, rightValueString); + default: + throw RInternalError.shouldNotReachHere(); + } + default: + throw RInternalError.shouldNotReachHere(); + } + } + } +} + +final class BinaryMapVectorNode extends BinaryMapNode { @Child private VectorMapBinaryInternalNode vectorNode; - @Child private BinaryMapFunctionNode function; @Child private CopyAttributesNode copyAttributes; @Child private GetDimAttributeNode getLeftDimNode = GetDimAttributeNode.create(); @Child private GetDimAttributeNode getRightDimNode = GetDimAttributeNode.create(); @Child private HasFixedAttributeNode hasLeftDimNode = HasFixedAttributeNode.createDim(); @Child private HasFixedAttributeNode hasRightDimNode = HasFixedAttributeNode.createDim(); + @Child private VectorAccess fastLeftAccess; + @Child private VectorAccess fastRightAccess; + @Child private VectorAccess resultAccess; + // profiles - private final Class<? extends RAbstractVector> leftClass; - private final Class<? extends RAbstractVector> rightClass; - private final VectorLengthProfile leftLengthProfile = VectorLengthProfile.create(); - private final VectorLengthProfile rightLengthProfile = VectorLengthProfile.create(); + private final VectorLengthProfile leftLengthProfile; + private final VectorLengthProfile rightLengthProfile; private final ConditionProfile dimensionsProfile; private final ConditionProfile maxLengthProfile; - private final ConditionProfile leftIsNAProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile rightIsNAProfile = ConditionProfile.createBinaryProfile(); - private final ConditionProfile seenEmpty = ConditionProfile.createBinaryProfile(); + private final ConditionProfile seenEmpty; private final ConditionProfile shareLeft; private final ConditionProfile shareRight; - private final RType argumentType; - private final RType resultType; + private final ConditionProfile leftIsNAProfile; + private final ConditionProfile rightIsNAProfile; // compile-time optimization flags - private final boolean scalarTypes; private final boolean mayContainMetadata; private final boolean mayFoldConstantTime; private final boolean mayShareLeft; private final boolean mayShareRight; - - private BinaryMapNode(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType, boolean copyAttributes) { - this.function = function; - this.leftClass = left.getClass(); - this.rightClass = right.getClass(); + private final boolean isGeneric; + + BinaryMapVectorNode(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType, boolean copyAttributes, boolean isGeneric) { + super(function, left, right, argumentType, resultType); + this.leftLengthProfile = VectorLengthProfile.create(); + this.rightLengthProfile = VectorLengthProfile.create(); + this.seenEmpty = ConditionProfile.createBinaryProfile(); + this.fastLeftAccess = isGeneric ? null : left.access(); + this.fastRightAccess = isGeneric ? null : right.access(); this.vectorNode = VectorMapBinaryInternalNode.create(resultType, argumentType); - this.scalarTypes = left instanceof RScalarVector && right instanceof RScalarVector; boolean leftVectorImpl = RVector.class.isAssignableFrom(leftClass); boolean rightVectorImpl = RVector.class.isAssignableFrom(rightClass); this.mayContainMetadata = leftVectorImpl || rightVectorImpl; this.mayFoldConstantTime = function.mayFoldConstantTime(leftClass, rightClass); + this.leftIsNAProfile = mayFoldConstantTime ? ConditionProfile.createBinaryProfile() : null; + this.rightIsNAProfile = mayFoldConstantTime ? ConditionProfile.createBinaryProfile() : null; this.mayShareLeft = left.getRType() == resultType && leftVectorImpl; this.mayShareRight = right.getRType() == resultType && rightVectorImpl; - this.argumentType = argumentType; - this.resultType = resultType; - this.maxLengthProfile = ConditionProfile.createBinaryProfile(); - // lazily create profiles only if needed to avoid unnecessary allocations this.shareLeft = mayShareLeft ? ConditionProfile.createBinaryProfile() : null; this.shareRight = mayShareRight ? ConditionProfile.createBinaryProfile() : null; this.dimensionsProfile = mayContainMetadata ? ConditionProfile.createBinaryProfile() : null; this.copyAttributes = mayContainMetadata ? CopyAttributesNodeGen.create(copyAttributes) : null; + this.maxLengthProfile = ConditionProfile.createBinaryProfile(); + this.isGeneric = isGeneric; } - public static BinaryMapNode create(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType, boolean copyAttributes) { - return new BinaryMapNode(function, left, right, argumentType, resultType, copyAttributes); - } - - public boolean isSupported(Object left, Object right) { - return left.getClass() == leftClass && right.getClass() == rightClass; + @Override + public boolean isSupported(RAbstractVector left, RAbstractVector right) { + return left.getClass() == leftClass && right.getClass() == rightClass && (isGeneric || fastLeftAccess.supports(left) && fastRightAccess.supports(right)); } - public Object apply(Object originalLeft, Object originalRight) { + @Override + public Object apply(RAbstractVector originalLeft, RAbstractVector originalRight) { assert isSupported(originalLeft, originalRight); RAbstractVector left = leftClass.cast(originalLeft); RAbstractVector right = rightClass.cast(originalRight); - RAbstractVector leftCast = left.castSafe(argumentType, leftIsNAProfile, false); - RAbstractVector rightCast = right.castSafe(argumentType, rightIsNAProfile, false); + function.enable(left, right); - assert leftCast != null; - assert rightCast != null; - - function.enable(leftCast, rightCast); + if (mayContainMetadata && (dimensionsProfile.profile(hasLeftDimNode.execute(left) && hasRightDimNode.execute(right)))) { + if (differentDimensions(left, right)) { + throw error(RError.Message.NON_CONFORMABLE_ARRAYS); + } + } - if (scalarTypes) { - assert left.getLength() == 1; - assert right.getLength() == 1; - return applyScalar(leftCast, rightCast); - } else { - int leftLength = leftLengthProfile.profile(left.getLength()); - int rightLength = rightLengthProfile.profile(right.getLength()); - return applyVectorized(left, leftCast, leftLength, right, rightCast, rightLength); + VectorAccess leftAccess = isGeneric ? left.slowPathAccess() : fastLeftAccess; + VectorAccess rightAccess = isGeneric ? right.slowPathAccess() : fastRightAccess; + try (SequentialIterator leftIter = leftAccess.access(left); + SequentialIterator rightIter = rightAccess.access(right)) { + RAbstractVector target = null; + int leftLength = leftLengthProfile.profile(leftAccess.getLength(leftIter)); + int rightLength = rightLengthProfile.profile(rightAccess.getLength(rightIter)); + if (seenEmpty.profile(leftLength == 0 || rightLength == 0)) { + /* + * It is safe to skip attribute handling here as they are never copied if length is + * 0 of either side. Note that dimension check still needs to be performed. + */ + return resultType.getEmpty(); + } + if (mayFoldConstantTime) { + target = function.tryFoldConstantTime(left.castSafe(argumentType, leftIsNAProfile, false), leftLength, right.castSafe(argumentType, rightIsNAProfile, false), rightLength); + } + if (target == null) { + int maxLength = maxLengthProfile.profile(leftLength >= rightLength) ? leftLength : rightLength; + + assert left.getLength() == leftLength; + assert right.getLength() == rightLength; + if (mayShareLeft && left.getRType() == resultType && shareLeft.profile(leftLength == maxLength && ((RShareable) left).isTemporary())) { + target = left; + vectorNode.execute(function, leftLength, rightLength, leftAccess, leftIter, leftAccess, leftIter, rightAccess, rightIter); + } else if (mayShareRight && right.getRType() == resultType && shareRight.profile(rightLength == maxLength && ((RShareable) right).isTemporary())) { + target = right; + vectorNode.execute(function, leftLength, rightLength, rightAccess, rightIter, leftAccess, leftIter, rightAccess, rightIter); + } else { + if (resultAccess == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + resultAccess = insert(VectorAccess.createNew(resultType)); + } + target = resultType.create(maxLength, false); + try (SequentialIterator resultIter = resultAccess.access(target)) { + vectorNode.execute(function, leftLength, rightLength, resultAccess, resultIter, leftAccess, leftIter, rightAccess, rightIter); + } + } + RBaseNode.reportWork(this, maxLength); + target.setComplete(function.isComplete()); + } + if (mayContainMetadata) { + target = copyAttributes.execute(target, left, leftLength, right, rightLength); + } + return target; } } @@ -166,353 +284,308 @@ public final class BinaryMapNode extends RBaseNode { } return false; } +} + +abstract class VectorMapBinaryInternalNode extends RBaseNode { + + private abstract static class MapBinaryIndexedAction { + public abstract void perform(BinaryMapFunctionNode action, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter); + } + + private static final MapBinaryIndexedAction LOGICAL_LOGICAL = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setLogical(resultIter, arithmetic.applyLogical(left.getLogical(leftIter), right.getLogical(rightIter))); + } + }; + private static final MapBinaryIndexedAction LOGICAL_INTEGER = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setLogical(resultIter, arithmetic.applyLogical(left.getInt(leftIter), right.getInt(rightIter))); + } + }; + private static final MapBinaryIndexedAction LOGICAL_DOUBLE = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setLogical(resultIter, arithmetic.applyLogical(left.getDouble(leftIter), right.getDouble(rightIter))); + } + }; + private static final MapBinaryIndexedAction LOGICAL_COMPLEX = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setLogical(resultIter, arithmetic.applyLogical(left.getComplex(leftIter), right.getComplex(rightIter))); + } + }; + private static final MapBinaryIndexedAction LOGICAL_CHARACTER = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setLogical(resultIter, arithmetic.applyLogical(left.getString(leftIter), right.getString(rightIter))); + } + }; + private static final MapBinaryIndexedAction LOGICAL_RAW = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setLogical(resultIter, arithmetic.applyLogical(RRuntime.raw2int(left.getRaw(leftIter)), RRuntime.raw2int(right.getRaw(rightIter)))); + } + }; + private static final MapBinaryIndexedAction RAW_RAW = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setRaw(resultIter, arithmetic.applyRaw(left.getRaw(leftIter), right.getRaw(rightIter))); + } + }; + private static final MapBinaryIndexedAction INTEGER_INTEGER = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setInt(resultIter, arithmetic.applyInteger(left.getInt(leftIter), right.getInt(rightIter))); + } + }; + private static final MapBinaryIndexedAction DOUBLE_INTEGER = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setDouble(resultIter, arithmetic.applyDouble(left.getInt(leftIter), right.getInt(rightIter))); + } + }; + private static final MapBinaryIndexedAction DOUBLE = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setDouble(resultIter, arithmetic.applyDouble(left.getDouble(leftIter), right.getDouble(rightIter))); + } + }; + private static final MapBinaryIndexedAction COMPLEX = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + RComplex value = arithmetic.applyComplex(left.getComplex(leftIter), right.getComplex(rightIter)); + result.setComplex(resultIter, value.getRealPart(), value.getImaginaryPart()); + } + }; + private static final MapBinaryIndexedAction CHARACTER = new MapBinaryIndexedAction() { + @Override + public void perform(BinaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + result.setString(resultIter, arithmetic.applyCharacter(left.getString(leftIter), right.getString(rightIter))); + } + }; + + private final MapBinaryIndexedAction indexedAction; + + protected VectorMapBinaryInternalNode(RType resultType, RType argumentType) { + this.indexedAction = createIndexedAction(resultType, argumentType); + } - private Object applyScalar(RAbstractVector left, RAbstractVector right) { - switch (argumentType) { + public static VectorMapBinaryInternalNode create(RType resultType, RType argumentType) { + return VectorMapBinaryInternalNodeGen.create(resultType, argumentType); + } + + private static MapBinaryIndexedAction createIndexedAction(RType resultType, RType argumentType) { + switch (resultType) { case Raw: - byte leftValueRaw = ((RAbstractRawVector) left).getRawDataAt(0); - byte rightValueRaw = ((RAbstractRawVector) right).getRawDataAt(0); - switch (resultType) { - case Raw: - return RRaw.valueOf(function.applyRaw(leftValueRaw, rightValueRaw)); - case Logical: - return function.applyLogical(RRuntime.raw2int(leftValueRaw), RRuntime.raw2int(rightValueRaw)); - default: - throw RInternalError.shouldNotReachHere(); - } + assert argumentType == RType.Raw; + return RAW_RAW; case Logical: - byte leftValueLogical = ((RAbstractLogicalVector) left).getDataAt(0); - byte rightValueLogical = ((RAbstractLogicalVector) right).getDataAt(0); - return function.applyLogical(leftValueLogical, rightValueLogical); - case Integer: - int leftValueInt = ((RAbstractIntVector) left).getDataAt(0); - int rightValueInt = ((RAbstractIntVector) right).getDataAt(0); - switch (resultType) { + switch (argumentType) { + case Raw: + return LOGICAL_RAW; case Logical: - return function.applyLogical(leftValueInt, rightValueInt); + return LOGICAL_LOGICAL; case Integer: - return function.applyInteger(leftValueInt, rightValueInt); + return LOGICAL_INTEGER; case Double: - return function.applyDouble(leftValueInt, rightValueInt); + return LOGICAL_DOUBLE; + case Complex: + return LOGICAL_COMPLEX; + case Character: + return LOGICAL_CHARACTER; default: throw RInternalError.shouldNotReachHere(); } + case Integer: + assert argumentType == RType.Integer; + return INTEGER_INTEGER; case Double: - double leftValueDouble = ((RAbstractDoubleVector) left).getDataAt(0); - double rightValueDouble = ((RAbstractDoubleVector) right).getDataAt(0); - switch (resultType) { - case Logical: - return function.applyLogical(leftValueDouble, rightValueDouble); + switch (argumentType) { + case Integer: + return DOUBLE_INTEGER; case Double: - return function.applyDouble(leftValueDouble, rightValueDouble); + return DOUBLE; default: throw RInternalError.shouldNotReachHere(); } case Complex: - RComplex leftValueComplex = ((RAbstractComplexVector) left).getDataAt(0); - RComplex rightValueComplex = ((RAbstractComplexVector) right).getDataAt(0); - switch (resultType) { - case Logical: - return function.applyLogical(leftValueComplex, rightValueComplex); - case Complex: - return function.applyComplex(leftValueComplex, rightValueComplex); - default: - throw RInternalError.shouldNotReachHere(); - } + assert argumentType == RType.Complex; + return COMPLEX; case Character: - String leftValueString = ((RAbstractStringVector) left).getDataAt(0); - String rightValueString = ((RAbstractStringVector) right).getDataAt(0); - switch (resultType) { - case Logical: - return function.applyLogical(leftValueString, rightValueString); - default: - throw RInternalError.shouldNotReachHere(); - } + assert argumentType == RType.Character; + return CHARACTER; default: throw RInternalError.shouldNotReachHere(); } } - private Object applyVectorized(RAbstractVector left, RAbstractVector leftCast, int leftLength, RAbstractVector right, RAbstractVector rightCast, int rightLength) { - if (mayContainMetadata && (dimensionsProfile.profile(hasLeftDimNode.execute(left) && hasRightDimNode.execute(right)))) { - if (differentDimensions(left, right)) { - throw error(RError.Message.NON_CONFORMABLE_ARRAYS); - } - } - - if (seenEmpty.profile(leftLength == 0 || rightLength == 0)) { - /* - * It is safe to skip attribute handling here as they are never copied if length is 0 of - * either side. Note that dimension check still needs to be performed. - */ - return resultType.getEmpty(); - } + public abstract void execute(BinaryMapFunctionNode node, int leftLength, int rightLength, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter); - RAbstractVector target = null; - if (mayFoldConstantTime) { - target = function.tryFoldConstantTime(leftCast, leftLength, rightCast, rightLength); - } - if (target == null) { - int maxLength = maxLengthProfile.profile(leftLength >= rightLength) ? leftLength : rightLength; - RVector<?> targetVec = createOrShareVector(leftLength, left, rightLength, right, maxLength); - target = targetVec; - - assert left.getLength() == leftLength; - assert right.getLength() == rightLength; - assert leftCast.getRType() == argumentType; - assert rightCast.getRType() == argumentType; - - vectorNode.execute(function, targetVec, leftCast, leftLength, rightCast, rightLength); - RBaseNode.reportWork(this, maxLength); - target.setComplete(function.isComplete()); + @Specialization(guards = {"leftLength == 1", "rightLength == 1"}) + protected void doScalarScalar(BinaryMapFunctionNode node, @SuppressWarnings("unused") int leftLength, @SuppressWarnings("unused") int rightLength, VectorAccess result, + SequentialIterator resultIter, VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter) { + left.next(leftIter); + right.next(rightIter); + if (result != right && result != left) { + result.next(resultIter); } - if (mayContainMetadata) { - target = copyAttributes.execute(target, left, leftLength, right, rightLength); - } - return target; + indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter); } - private RVector<?> createOrShareVector(int leftLength, RAbstractVector left, int rightLength, RAbstractVector right, int maxLength) { - if (mayShareLeft && left.getRType() == resultType && shareLeft.profile(leftLength == maxLength && ((RShareable) left).isTemporary()) && left instanceof RVector<?>) { - return (RVector<?>) left; - } - if (mayShareRight && right.getRType() == resultType && shareRight.profile(rightLength == maxLength && ((RShareable) right).isTemporary()) && right instanceof RVector<?>) { - return (RVector<?>) right; + @Specialization(replaces = "doScalarScalar", guards = {"leftLength == 1"}) + protected void doScalarVector(BinaryMapFunctionNode node, @SuppressWarnings("unused") int leftLength, int rightLength, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter, + @Cached("createCountingProfile()") LoopConditionProfile profile) { + profile.profileCounted(rightLength); + left.next(leftIter); + while (profile.inject(right.next(rightIter))) { + if (result != right && result != left) { + result.next(resultIter); + } + indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter); } - return resultType.create(maxLength, false); } - @ImportStatic(Utils.class) - protected abstract static class VectorMapBinaryInternalNode extends RBaseNode { - - private static final MapBinaryIndexedAction<Byte> LOGICAL_LOGICAL = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal); - private static final MapBinaryIndexedAction<Integer> LOGICAL_INTEGER = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal); - private static final MapBinaryIndexedAction<Double> LOGICAL_DOUBLE = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal); - private static final MapBinaryIndexedAction<RComplex> LOGICAL_COMPLEX = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal); - private static final MapBinaryIndexedAction<String> LOGICAL_CHARACTER = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(leftVal, rightVal); - private static final MapBinaryIndexedAction<Byte> LOGICAL_RAW = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyLogical(RRuntime.raw2int(leftVal), RRuntime.raw2int(rightVal)); - private static final MapBinaryIndexedAction<Byte> RAW_RAW = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyRaw(leftVal, rightVal); - private static final MapBinaryIndexedAction<Integer> INTEGER_INTEGER = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyInteger(leftVal, rightVal); - private static final MapBinaryIndexedAction<Integer> DOUBLE_INTEGER = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyDouble(leftVal, rightVal); - private static final MapBinaryIndexedAction<Double> DOUBLE = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyDouble(leftVal, rightVal); - private static final MapBinaryIndexedAction<RComplex> COMPLEX = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyComplex(leftVal, rightVal); - private static final MapBinaryIndexedAction<String> CHARACTER = // - (arithmetic, leftVal, rightVal) -> arithmetic.applyCharacter(leftVal, rightVal); - - private final MapBinaryIndexedAction<Object> indexedAction; - - @Child private GetDataStore getTargetDataStore = GetDataStore.create(); - @Child private SetDataAt targetSetDataAt; - - @SuppressWarnings("unchecked") - protected VectorMapBinaryInternalNode(RType resultType, RType argumentType) { - this.indexedAction = (MapBinaryIndexedAction<Object>) createIndexedAction(resultType, argumentType); - this.targetSetDataAt = Utils.createSetDataAtNode(resultType); + @Specialization(replaces = "doScalarScalar", guards = {"rightLength == 1"}) + protected void doVectorScalar(BinaryMapFunctionNode node, int leftLength, @SuppressWarnings("unused") int rightLength, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter, + @Cached("createCountingProfile()") LoopConditionProfile profile) { + profile.profileCounted(leftLength); + right.next(rightIter); + while (profile.inject(left.next(leftIter))) { + if (result != left && result != right) { + result.next(resultIter); + } + indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter); } + } - public static VectorMapBinaryInternalNode create(RType resultType, RType argumentType) { - return VectorMapBinaryInternalNodeGen.create(resultType, argumentType); + @Specialization(guards = {"leftLength == rightLength"}) + protected void doSameLength(BinaryMapFunctionNode node, int leftLength, @SuppressWarnings("unused") int rightLength, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter, + @Cached("createCountingProfile()") LoopConditionProfile profile) { + profile.profileCounted(leftLength); + while (profile.inject(left.next(leftIter))) { + right.next(rightIter); + if (result != left && result != right) { + result.next(resultIter); + } + indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter); } + } - private static MapBinaryIndexedAction<?> createIndexedAction(RType resultType, RType argumentType) { - switch (resultType) { - case Raw: - assert argumentType == RType.Raw; - return RAW_RAW; - case Logical: - switch (argumentType) { - case Raw: - return LOGICAL_RAW; - case Logical: - return LOGICAL_LOGICAL; - case Integer: - return LOGICAL_INTEGER; - case Double: - return LOGICAL_DOUBLE; - case Complex: - return LOGICAL_COMPLEX; - case Character: - return LOGICAL_CHARACTER; - default: - throw RInternalError.shouldNotReachHere(); + @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"leftLength >= rightLength"}) + protected void doMultiplesLeft(BinaryMapFunctionNode node, int leftLength, int rightLength, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter, + @Cached("createCountingProfile()") LoopConditionProfile leftProfile, + @Cached("createCountingProfile()") LoopConditionProfile rightProfile, + @Cached("createBinaryProfile()") ConditionProfile smallRemainderProfile) { + assert result != right; + leftProfile.profileCounted(leftLength); + rightProfile.profileCounted(rightLength); + while (leftProfile.inject(leftIter.getIndex() + 1 < leftLength)) { + right.reset(rightIter); + if (smallRemainderProfile.profile((leftLength - leftIter.getIndex() - 1) >= rightLength)) { + // we need at least rightLength more elements + while (rightProfile.inject(right.next(rightIter)) && leftProfile.inject(left.next(leftIter))) { + if (result != left) { + result.next(resultIter); } - case Integer: - assert argumentType == RType.Integer; - return INTEGER_INTEGER; - case Double: - switch (argumentType) { - case Integer: - return DOUBLE_INTEGER; - case Double: - return DOUBLE; - default: - throw RInternalError.shouldNotReachHere(); + indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter); + } + } else { + while (rightProfile.inject(right.next(rightIter)) && leftProfile.inject(left.next(leftIter))) { + if (result != left) { + result.next(resultIter); } - case Complex: - assert argumentType == RType.Complex; - return COMPLEX; - case Character: - assert argumentType == RType.Character; - return CHARACTER; - default: - throw RInternalError.shouldNotReachHere(); - } - } - - public abstract void execute(BinaryMapFunctionNode node, RVector<?> store, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength); - - @Specialization(guards = {"leftLength == 1", "rightLength == 1"}) - @SuppressWarnings("unused") - protected void doScalarScalar(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength, - @Cached("createIterator()") VectorIterator.Generic leftIterator, - @Cached("createIterator()") VectorIterator.Generic rightIterator) { - Object itLeft = leftIterator.init(left); - Object itRight = rightIterator.init(right); - Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight)); - targetSetDataAt.setDataAtAsObject(result, getTargetDataStore.execute(result), 0, value); - } - - @Specialization(replaces = "doScalarScalar", guards = {"leftLength == 1"}) - @SuppressWarnings("unused") - protected void doScalarVector(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength, - @Cached("createIterator()") VectorIterator.Generic leftIterator, - @Cached("createIterator()") VectorIterator.Generic rightIterator, - @Cached("createCountingProfile()") LoopConditionProfile profile) { - profile.profileCounted(rightLength); - Object itLeft = leftIterator.init(left); - Object itRight = rightIterator.init(right); - Object resultStore = getTargetDataStore.execute(result); - Object leftValue = leftIterator.next(left, itLeft); - for (int i = 0; profile.inject(i < rightLength); ++i) { - Object value = indexedAction.perform(node, leftValue, rightIterator.next(right, itRight)); - targetSetDataAt.setDataAtAsObject(result, resultStore, i, value); + indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter); + } + RError.warning(this, RError.Message.LENGTH_NOT_MULTI); } } + } - @Specialization(replaces = "doScalarScalar", guards = {"rightLength == 1"}) - @SuppressWarnings("unused") - protected void doVectorScalar(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength, - @Cached("createIterator()") VectorIterator.Generic leftIterator, - @Cached("createIterator()") VectorIterator.Generic rightIterator, - @Cached("createCountingProfile()") LoopConditionProfile profile) { - profile.profileCounted(leftLength); - Object itLeft = leftIterator.init(left); - Object itRight = rightIterator.init(right); - Object resultStore = getTargetDataStore.execute(result); - Object rightValue = rightIterator.next(right, itRight); - for (int i = 0; profile.inject(i < leftLength); ++i) { - Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightValue); - targetSetDataAt.setDataAtAsObject(result, resultStore, i, value); + @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"rightLength >= leftLength"}) + protected void doMultiplesRight(BinaryMapFunctionNode node, int leftLength, int rightLength, VectorAccess result, SequentialIterator resultIter, + VectorAccess left, SequentialIterator leftIter, VectorAccess right, SequentialIterator rightIter, + @Cached("createCountingProfile()") LoopConditionProfile leftProfile, + @Cached("createCountingProfile()") LoopConditionProfile rightProfile, + @Cached("createBinaryProfile()") ConditionProfile smallRemainderProfile) { + assert result != left; + leftProfile.profileCounted(leftLength); + rightProfile.profileCounted(rightLength); + while (rightProfile.inject(rightIter.getIndex() + 1 < rightLength)) { + left.reset(leftIter); + if (smallRemainderProfile.profile((rightLength - rightIter.getIndex() - 1) >= leftLength)) { + // we need at least leftLength more elements + while (leftProfile.inject(left.next(leftIter)) && rightProfile.inject(right.next(rightIter))) { + if (result != right) { + result.next(resultIter); + } + indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter); + } + } else { + while (leftProfile.inject(left.next(leftIter)) && rightProfile.inject(right.next(rightIter))) { + if (result != right) { + result.next(resultIter); + } + indexedAction.perform(node, result, resultIter, left, leftIter, right, rightIter); + } + RError.warning(this, RError.Message.LENGTH_NOT_MULTI); } } + } +} - @Specialization(guards = {"leftLength == rightLength"}) - @SuppressWarnings("unused") - protected void doSameLength(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength, - @Cached("createIterator()") VectorIterator.Generic leftIterator, - @Cached("createIterator()") VectorIterator.Generic rightIterator, - @Cached("createCountingProfile()") LoopConditionProfile profile) { - profile.profileCounted(leftLength); - Object itLeft = leftIterator.init(left); - Object itRight = rightIterator.init(right); - Object resultStore = getTargetDataStore.execute(result); - for (int i = 0; profile.inject(i < leftLength); ++i) { - Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight)); - targetSetDataAt.setDataAtAsObject(result, resultStore, i, value); - } - } +/** + * Implements a binary map operation that maps two vectors into a single result vector of the + * maximum size of both vectors. Vectors with smaller length are repeated. The actual implementation + * is provided using a {@link BinaryMapFunctionNode}. + * + * The implementation tries to share input vectors if they are implementing {@link RShareable}. + */ +public abstract class BinaryMapNode extends RBaseNode { - protected static boolean multiplesMinMax(int min, int max) { - return max % min == 0; - } + @Child protected BinaryMapFunctionNode function; + protected final Class<? extends RAbstractVector> leftClass; + protected final Class<? extends RAbstractVector> rightClass; + protected final RType argumentType; + protected final RType resultType; - @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(leftLength, rightLength)"}) - protected void doMultiplesLeft(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength, - @Cached("createIteratorWrapAround()") VectorIterator.Generic leftIterator, - @Cached("createIterator()") VectorIterator.Generic rightIterator, - @Cached("createCountingProfile()") LoopConditionProfile leftProfile, - @Cached("createCountingProfile()") LoopConditionProfile rightProfile) { - int j = 0; - rightProfile.profileCounted(rightLength / leftLength); - Object itLeft = leftIterator.init(left); - Object itRight = rightIterator.init(right); - Object resultStore = getTargetDataStore.execute(result); - while (rightProfile.inject(j < rightLength)) { - leftProfile.profileCounted(leftLength); - for (int k = 0; leftProfile.inject(k < leftLength); k++) { - Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight)); - targetSetDataAt.setDataAtAsObject(result, resultStore, j, value); - j++; - } - } - } + protected BinaryMapNode(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType) { + this.function = function; + this.leftClass = left.getClass(); + this.rightClass = right.getClass(); + this.argumentType = argumentType; + this.resultType = resultType; + } - @Specialization(replaces = {"doVectorScalar", "doScalarVector", "doSameLength"}, guards = {"multiplesMinMax(rightLength, leftLength)"}) - protected void doMultiplesRight(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength, - @Cached("createIterator()") VectorIterator.Generic leftIterator, - @Cached("createIteratorWrapAround()") VectorIterator.Generic rightIterator, - @Cached("createCountingProfile()") LoopConditionProfile leftProfile, - @Cached("createCountingProfile()") LoopConditionProfile rightProfile) { - int j = 0; - leftProfile.profileCounted(leftLength / rightLength); - Object itLeft = leftIterator.init(left); - Object itRight = rightIterator.init(right); - Object resultStore = getTargetDataStore.execute(result); - while (leftProfile.inject(j < leftLength)) { - rightProfile.profileCounted(rightLength); - for (int k = 0; rightProfile.inject(k < rightLength); k++) { - Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight)); - targetSetDataAt.setDataAtAsObject(result, resultStore, j, value); - j++; - } - } + public static BinaryMapNode create(BinaryMapFunctionNode function, RAbstractVector left, RAbstractVector right, RType argumentType, RType resultType, boolean copyAttributes, boolean isGeneric) { + if (left instanceof RScalarVector && right instanceof RScalarVector) { + return new BinaryMapScalarNode(function, left, right, argumentType, resultType); + } else { + return new BinaryMapVectorNode(function, left, right, argumentType, resultType, copyAttributes, isGeneric); } + } - protected static boolean multiples(int leftLength, int rightLength) { - int min; - int max; - if (leftLength >= rightLength) { - min = rightLength; - max = leftLength; - } else { - min = leftLength; - max = rightLength; - } - return max % min == 0; - } + public abstract boolean isSupported(RAbstractVector left, RAbstractVector right); - @Specialization(guards = {"!multiples(leftLength, rightLength)"}) - protected void doNoMultiples(BinaryMapFunctionNode node, RVector<?> result, RAbstractVector left, int leftLength, RAbstractVector right, int rightLength, - @Cached("createIteratorWrapAround()") VectorIterator.Generic leftIterator, - @Cached("createIteratorWrapAround()") VectorIterator.Generic rightIterator, - @Cached("createCountingProfile()") LoopConditionProfile profile, - @Cached("createBinaryProfile()") ConditionProfile leftIncModProfile, - @Cached("createBinaryProfile()") ConditionProfile rightIncModProfile) { - int max = Math.max(leftLength, rightLength); - profile.profileCounted(max); - Object itLeft = leftIterator.init(left); - Object itRight = rightIterator.init(right); - Object resultStore = getTargetDataStore.execute(result); - for (int i = 0; profile.inject(i < max); ++i) { - Object value = indexedAction.perform(node, leftIterator.next(left, itLeft), rightIterator.next(right, itRight)); - targetSetDataAt.setDataAtAsObject(result, resultStore, i, value); - } - RError.warning(this, RError.Message.LENGTH_NOT_MULTI); - } + public abstract Object apply(RAbstractVector originalLeft, RAbstractVector originalRight); - private interface MapBinaryIndexedAction<V> { - Object perform(BinaryMapFunctionNode action, V left, V right); - } - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java index aaa72efdec80a239329d21e901f04e54825e7a27..1b997142d4066f3258265d10921a4ce32d70d39f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/UnaryMapNode.java @@ -25,7 +25,6 @@ package com.oracle.truffle.r.nodes.primitive; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; @@ -35,7 +34,6 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAt import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.SetDimAttributeNode; -import com.oracle.truffle.r.nodes.primitive.UnaryMapNodeFactory.MapUnaryVectorInternalNodeGen; import com.oracle.truffle.r.nodes.profile.VectorLengthProfile; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RType; @@ -43,121 +41,130 @@ import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RScalarVector; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RVector; -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.RAbstractVector; -import com.oracle.truffle.r.runtime.data.nodes.GetDataStore; -import com.oracle.truffle.r.runtime.data.nodes.SetDataAt; -import com.oracle.truffle.r.runtime.data.nodes.VectorIterator; +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; import com.oracle.truffle.r.runtime.nodes.RBaseNode; -public final class UnaryMapNode extends RBaseNode { +final class UnaryMapScalarNode extends UnaryMapNode { + + @Child private VectorAccess operandAccess; + + UnaryMapScalarNode(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType) { + super(scalarNode, operand, argumentType, resultType); + this.operandAccess = operand.access(); + } + + @Override + public boolean isSupported(RAbstractVector operand) { + return operandAccess.supports(operand); + } + + @Override + public Object apply(RAbstractVector operand) { + assert isSupported(operand); + + function.enable(operand); + assert operand.getLength() == 1; + + try (RandomIterator iter = operandAccess.randomAccess(operand)) { + switch (argumentType) { + case Logical: + return function.applyLogical(operandAccess.getLogical(iter, 0)); + case Integer: + return function.applyInteger(operandAccess.getInt(iter, 0)); + case Double: + return function.applyDouble(operandAccess.getDouble(iter, 0)); + case Complex: + switch (resultType) { + case Double: + return function.applyDouble(operandAccess.getComplex(iter, 0)); + case Complex: + return function.applyComplex(operandAccess.getComplex(iter, 0)); + default: + throw RInternalError.shouldNotReachHere(); + } + default: + throw RInternalError.shouldNotReachHere(); + } + } + } +} + +final class UnaryMapVectorNode extends UnaryMapNode { - @Child private UnaryMapFunctionNode scalarNode; @Child private MapUnaryVectorInternalNode vectorNode; @Child private GetDimAttributeNode getDimNode; @Child private SetDimAttributeNode setDimNode; @Child private GetNamesAttributeNode getNamesNode = GetNamesAttributeNode.create(); + @Child private VectorAccess fastOperandAccess; + @Child private VectorAccess resultAccess; // profiles - private final Class<? extends RAbstractVector> operandClass; private final VectorLengthProfile operandLengthProfile = VectorLengthProfile.create(); - private final ConditionProfile operandIsNAProfile = ConditionProfile.createBinaryProfile(); private final BranchProfile hasAttributesProfile; private final ConditionProfile shareOperand; // compile-time optimization flags - private final boolean scalarType; private final boolean mayContainMetadata; private final boolean mayFoldConstantTime; private final boolean mayShareOperand; + private final boolean isGeneric; - private UnaryMapNode(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType) { - this.scalarNode = scalarNode; + UnaryMapVectorNode(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType, boolean isGeneric) { + super(scalarNode, operand, argumentType, resultType); + this.fastOperandAccess = isGeneric ? null : operand.access(); this.vectorNode = MapUnaryVectorInternalNode.create(resultType, argumentType); - this.operandClass = operand.getClass(); - this.scalarType = operand instanceof RScalarVector; boolean operandVector = operand instanceof RVector; this.mayContainMetadata = operandVector; - this.mayFoldConstantTime = scalarNode.mayFoldConstantTime(operandClass); + this.mayFoldConstantTime = argumentType == operand.getRType() && scalarNode.mayFoldConstantTime(operandClass); this.mayShareOperand = operandVector; + this.isGeneric = isGeneric; // lazily create profiles only if needed to avoid unnecessary allocations - this.shareOperand = operandVector ? ConditionProfile.createBinaryProfile() : null; + this.shareOperand = mayShareOperand ? ConditionProfile.createBinaryProfile() : null; this.hasAttributesProfile = mayContainMetadata ? BranchProfile.create() : null; - } - - public static UnaryMapNode create(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType) { - return new UnaryMapNode(scalarNode, operand, argumentType, resultType); - } - public Class<? extends RAbstractVector> getOperandClass() { - return operandClass; } - public RType getArgumentType() { - return vectorNode.getArgumentType(); + @Override + public boolean isSupported(RAbstractVector operand) { + return operand.getClass() == operandClass && (isGeneric || fastOperandAccess.supports(operand)); } - public RType getResultType() { - return vectorNode.getResultType(); - } - - public boolean isSupported(Object operand) { - return operand.getClass() == operandClass; - } - - public Object apply(Object originalOperand) { + @Override + public Object apply(RAbstractVector originalOperand) { assert isSupported(originalOperand); RAbstractVector operand = operandClass.cast(originalOperand); + function.enable(operand); + int operandLength = operandLengthProfile.profile(operand.getLength()); - RAbstractVector operandCast = operand.castSafe(getArgumentType(), operandIsNAProfile); - - scalarNode.enable(operandCast); - if (scalarType) { - assert operand.getLength() == 1; - return scalarOperation(operandCast); - } else { - int operandLength = operandLengthProfile.profile(operand.getLength()); - return vectorOperation(operand, operandCast, operandLength); - } - } - - private Object scalarOperation(RAbstractVector operand) { - switch (getArgumentType()) { - case Logical: - return scalarNode.applyLogical(((RAbstractLogicalVector) operand).getDataAt(0)); - case Integer: - return scalarNode.applyInteger(((RAbstractIntVector) operand).getDataAt(0)); - case Double: - return scalarNode.applyDouble(((RAbstractDoubleVector) operand).getDataAt(0)); - case Complex: - switch (getResultType()) { - case Double: - return scalarNode.applyDouble(((RAbstractComplexVector) operand).getDataAt(0)); - case Complex: - return scalarNode.applyComplex(((RAbstractComplexVector) operand).getDataAt(0)); - default: - throw RInternalError.shouldNotReachHere(); - } - default: - throw RInternalError.shouldNotReachHere(); - } - } - - private Object vectorOperation(RAbstractVector operand, RAbstractVector operandCast, int operandLength) { RAbstractVector target = null; if (mayFoldConstantTime) { - target = scalarNode.tryFoldConstantTime(operandCast, operandLength); + target = function.tryFoldConstantTime(operand, operandLength); } if (target == null) { - RVector<?> targetVec = createOrShareVector(operandLength, operand); - target = targetVec; - vectorNode.apply(scalarNode, targetVec, operandCast, operandLength); + VectorAccess operandAccess = isGeneric ? operand.slowPathAccess() : fastOperandAccess; + try (SequentialIterator operandIter = operandAccess.access(operand)) { + if (mayShareOperand && operand.getRType() == resultType && shareOperand.profile(((RShareable) operand).isTemporary())) { + target = operand; + vectorNode.execute(function, operandLength, operandAccess, operandIter, operandAccess, operandIter); + } else { + if (resultAccess == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + target = resultType.create(operandLength, false); + resultAccess = insert(target.access()); + } else { + target = resultType.create(operandLength, false); + } + try (SequentialIterator resultIter = resultAccess.access(target)) { + vectorNode.execute(function, operandLength, resultAccess, resultIter, operandAccess, operandIter); + } + } + } RBaseNode.reportWork(this, operandLength); - target.setComplete(scalarNode.isComplete()); + target.setComplete(function.isComplete()); } if (mayContainMetadata) { target = handleMetadata(target, operand); @@ -165,14 +172,6 @@ public final class UnaryMapNode extends RBaseNode { return target; } - private RVector<?> createOrShareVector(int operandLength, RAbstractVector operand) { - RType resultType = getResultType(); - if (mayShareOperand && operand.getRType() == resultType && shareOperand.profile(((RShareable) operand).isTemporary()) && operand instanceof RVector<?>) { - return (RVector<?>) operand; - } - return resultType.create(operandLength, false); - } - private RAbstractVector handleMetadata(RAbstractVector target, RAbstractVector operand) { RAbstractVector result = target; if (containsMetadata(operand) && operand != target) { @@ -213,107 +212,141 @@ public final class UnaryMapNode extends RBaseNode { result.copyRegAttributesFrom(attributeSource); result.copyNamesFrom(attributeSource); } +} - @ImportStatic(Utils.class) - protected abstract static class MapUnaryVectorInternalNode extends RBaseNode { - - private static final MapIndexedAction<Byte> LOGICAL = (arithmetic, value) -> arithmetic.applyLogical(value); - private static final MapIndexedAction<Integer> INTEGER = (arithmetic, value) -> arithmetic.applyInteger(value); - private static final MapIndexedAction<Double> DOUBLE = (arithmetic, value) -> arithmetic.applyDouble(value); - private static final MapIndexedAction<RComplex> COMPLEX = (arithmetic, value) -> arithmetic.applyComplex(value); - private static final MapIndexedAction<RComplex> DOUBLE_COMPLEX = (arithmetic, value) -> arithmetic.applyDouble(value); - private static final MapIndexedAction<String> CHARACTER = (arithmetic, value) -> arithmetic.applyCharacter(value); - - private final MapIndexedAction<Object> indexedAction; - private final RType argumentType; - private final RType resultType; - - @Child private GetDataStore getTargetDataStore = GetDataStore.create(); - @Child private SetDataAt targetSetDataAt; - - @SuppressWarnings("unchecked") - protected MapUnaryVectorInternalNode(RType resultType, RType argumentType) { - this.indexedAction = (MapIndexedAction<Object>) createIndexedAction(resultType, argumentType); - this.argumentType = argumentType; - this.resultType = resultType; - this.targetSetDataAt = Utils.createSetDataAtNode(resultType); - } +abstract class MapUnaryVectorInternalNode extends RBaseNode { - public RType getArgumentType() { - return argumentType; - } + private abstract static class MapIndexedAction { + public abstract void perform(UnaryMapFunctionNode action, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter); + } - public RType getResultType() { - return resultType; + private static final MapIndexedAction LOGICAL = new MapIndexedAction() { + @Override + public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) { + result.setLogical(resultIter, arithmetic.applyLogical(operand.getLogical(operandIter))); } - - public static MapUnaryVectorInternalNode create(RType resultType, RType argumentType) { - return MapUnaryVectorInternalNodeGen.create(resultType, argumentType); + }; + private static final MapIndexedAction INTEGER = new MapIndexedAction() { + @Override + public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) { + result.setInt(resultIter, arithmetic.applyInteger(operand.getInt(operandIter))); } - - private static MapIndexedAction<?> createIndexedAction(RType resultType, RType argumentType) { - switch (argumentType) { - case Logical: - return LOGICAL; - case Integer: - switch (resultType) { - case Integer: - return INTEGER; - case Double: - return DOUBLE; - default: - throw RInternalError.shouldNotReachHere(); - } - case Double: - return DOUBLE; - case Complex: - switch (resultType) { - case Double: - return DOUBLE_COMPLEX; - case Complex: - return COMPLEX; - default: - throw RInternalError.shouldNotReachHere(); - } - case Character: - return CHARACTER; - default: - throw RInternalError.shouldNotReachHere(); - } + }; + private static final MapIndexedAction DOUBLE = new MapIndexedAction() { + @Override + public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) { + result.setDouble(resultIter, arithmetic.applyDouble(operand.getDouble(operandIter))); + } + }; + private static final MapIndexedAction COMPLEX = new MapIndexedAction() { + @Override + public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) { + RComplex value = arithmetic.applyComplex(operand.getComplex(operandIter)); + result.setComplex(resultIter, value.getRealPart(), value.getImaginaryPart()); + } + }; + private static final MapIndexedAction DOUBLE_COMPLEX = new MapIndexedAction() { + @Override + public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) { + result.setDouble(resultIter, arithmetic.applyDouble(operand.getComplex(operandIter))); } + }; + private static final MapIndexedAction CHARACTER = new MapIndexedAction() { + @Override + public void perform(UnaryMapFunctionNode arithmetic, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter) { + result.setString(resultIter, arithmetic.applyCharacter(operand.getString(operandIter))); + } + }; + + private final MapIndexedAction indexedAction; + + protected MapUnaryVectorInternalNode(RType resultType, RType argumentType) { + this.indexedAction = createIndexedAction(resultType, argumentType); + } + + public static MapUnaryVectorInternalNode create(RType resultType, RType argumentType) { + return MapUnaryVectorInternalNodeGen.create(resultType, argumentType); + } - private void apply(UnaryMapFunctionNode scalarAction, RVector<?> target, RAbstractVector operand, int operandLength) { - assert operand.getLength() == operandLength; - assert operand.getRType() == argumentType; - executeInternal(scalarAction, target, operand, operandLength); + private static MapIndexedAction createIndexedAction(RType resultType, RType argumentType) { + switch (argumentType) { + case Logical: + return LOGICAL; + case Integer: + switch (resultType) { + case Integer: + return INTEGER; + case Double: + return DOUBLE; + default: + throw RInternalError.shouldNotReachHere(); + } + case Double: + return DOUBLE; + case Complex: + switch (resultType) { + case Double: + return DOUBLE_COMPLEX; + case Complex: + return COMPLEX; + default: + throw RInternalError.shouldNotReachHere(); + } + case Character: + return CHARACTER; + default: + throw RInternalError.shouldNotReachHere(); } + } - protected abstract void executeInternal(UnaryMapFunctionNode node, Object store, RAbstractVector operand, int operandLength); + protected abstract void execute(UnaryMapFunctionNode node, int operandLength, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter); - @Specialization(guards = {"operandLength == 1"}) - protected void doScalar(UnaryMapFunctionNode node, RVector<?> target, RAbstractVector operand, int operandLength, - @Cached("createIterator()") VectorIterator.Generic iterator) { - Object it = iterator.init(operand); - Object targetStore = getTargetDataStore.execute(target); - Object value = iterator.next(operand, it); - targetSetDataAt.setDataAtAsObject(target, targetStore, 0, indexedAction.perform(node, value)); + @Specialization(guards = {"operandLength == 1"}) + protected void doScalar(UnaryMapFunctionNode node, @SuppressWarnings("unused") int operandLength, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, + SequentialIterator operandIter) { + operand.next(operandIter); + if (result != operand) { + result.next(resultIter); } + indexedAction.perform(node, result, resultIter, operand, operandIter); + } - @Specialization(replaces = "doScalar") - protected void doScalarVector(UnaryMapFunctionNode node, RVector<?> target, RAbstractVector operand, int operandLength, - @Cached("createIterator()") VectorIterator.Generic iterator, - @Cached("createCountingProfile()") LoopConditionProfile profile) { - Object targetStore = getTargetDataStore.execute(target); - Object it = iterator.init(operand); - profile.profileCounted(operandLength); - for (int i = 0; profile.inject(i < operandLength); ++i) { - Object value = indexedAction.perform(node, iterator.next(operand, it)); - targetSetDataAt.setDataAtAsObject(target, targetStore, i, value); + @Specialization(replaces = "doScalar") + protected void doScalarVector(UnaryMapFunctionNode node, int operandLength, VectorAccess result, SequentialIterator resultIter, VectorAccess operand, SequentialIterator operandIter, + @Cached("createCountingProfile()") LoopConditionProfile profile) { + profile.profileCounted(operandLength); + while (profile.inject(operand.next(operandIter))) { + if (result != operand) { + result.next(resultIter); } + indexedAction.perform(node, result, resultIter, operand, operandIter); } + } +} + +public abstract class UnaryMapNode extends RBaseNode { - private interface MapIndexedAction<V> { - Object perform(UnaryMapFunctionNode action, V val); + @Child protected UnaryMapFunctionNode function; + protected final Class<? extends RAbstractVector> operandClass; + protected final RType argumentType; + protected final RType resultType; + + protected UnaryMapNode(UnaryMapFunctionNode function, RAbstractVector operand, RType argumentType, RType resultType) { + this.function = function; + this.operandClass = operand.getClass(); + this.argumentType = argumentType; + this.resultType = resultType; + } + + public static UnaryMapNode create(UnaryMapFunctionNode scalarNode, RAbstractVector operand, RType argumentType, RType resultType, boolean isGeneric) { + if (operand instanceof RScalarVector) { + return new UnaryMapScalarNode(scalarNode, operand, argumentType, resultType); + } else { + return new UnaryMapVectorNode(scalarNode, operand, argumentType, resultType, isGeneric); } } + + public abstract boolean isSupported(RAbstractVector operand); + + public abstract Object apply(RAbstractVector originalOperand); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java deleted file mode 100644 index 3ec6b0e3b7df1498e1acc23b969e9d1e86f2d34e..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/primitive/Utils.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.nodes.primitive; - -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.RType; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import com.oracle.truffle.r.runtime.data.nodes.SetDataAt; -import com.oracle.truffle.r.runtime.data.nodes.VectorIterator; - -abstract class Utils { - private Utils() { - } - - static SetDataAt createSetDataAtNode(RType type) { - switch (type) { - case Raw: - return SetDataAt.Raw.create(); - case Logical: - return SetDataAt.Logical.create(); - case Integer: - return SetDataAt.Int.create(); - case Double: - return SetDataAt.Double.create(); - case Complex: - return SetDataAt.Complex.create(); - case Character: - return SetDataAt.String.create(); - default: - throw RInternalError.shouldNotReachHere("BinaryMapNode unexpected result type " + type); - } - } - - static final class VecStore<T extends RAbstractVector> { - public final T vector; - public final Object store; - - VecStore(T vector, Object store) { - this.vector = vector; - this.store = store; - } - } - - public static VectorIterator.Generic createIterator() { - return VectorIterator.Generic.create(); - } - - public static VectorIterator.Generic createIteratorWrapAround() { - return VectorIterator.Generic.createWrapAround(); - } -} diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java index 8d3a0456e360fb32c4cb5eb2be2bc1a3a4a8bbea..aca07494f8ef2c9a0c228c16459d0d6c4aace97e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastStringBaseNode.java @@ -52,7 +52,7 @@ public abstract class CastStringBaseNode extends CastBaseNode { } protected String toString(Object value) { - return toString.executeString(value, false, ToStringNode.DEFAULT_SEPARATOR); + return toString.executeString(value, ToStringNode.DEFAULT_SEPARATOR); } @Specialization diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java index 2b45b6639ae5045f8d4941d354b0fc0bf958e45a..034b53109fddd47662cb8d0d4807a7398de58876 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastSymbolNode.java @@ -58,7 +58,7 @@ public abstract class CastSymbolNode extends CastBaseNode { public abstract Object executeSymbol(Object o); private String toString(Object value) { - return toString.executeString(value, true, ToStringNode.DEFAULT_SEPARATOR); + return toString.executeString(value, ToStringNode.DEFAULT_SEPARATOR); } @Specialization diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/NonNANode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/NonNANode.java index 34332663004f748fa4a1f766c26fce3e7bc82ed0..d3d18f87d3c2fe1179bd58ac9e66f64055a9f83e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/NonNANode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/NonNANode.java @@ -22,6 +22,7 @@ */ package com.oracle.truffle.r.nodes.unary; +import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.r.nodes.builtin.casts.MessageData; @@ -29,13 +30,10 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; -import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -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.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; public abstract class NonNANode extends CastNode { @@ -155,72 +153,26 @@ public abstract class NonNANode extends CastNode { return x; } - protected boolean isComplete(RAbstractContainer x) { - return x.isComplete(); - } - - @Specialization(guards = "isComplete(x)") + @Specialization(guards = "x.isComplete()") protected Object onCompleteContainer(RAbstractContainer x) { return x; } - @Specialization(guards = "!isComplete(x)") - protected Object onPossiblyIncompleteContainer(RAbstractIntVector x) { - int len = x.getLength(); - for (int i = 0; i < len; i++) { - if (RRuntime.isNA(x.getDataAt(i))) { - return handleNA(x); - } - } - return x; - } - - @Specialization(guards = "!isComplete(x)") - protected Object onPossiblyIncompleteContainer(RAbstractLogicalVector x) { - int len = x.getLength(); - for (int i = 0; i < len; i++) { - if (RRuntime.isNA(x.getDataAt(i))) { - return handleNA(x); - } - } - return x; - } - - @Specialization(guards = "!isComplete(x)") - protected Object onPossiblyIncompleteContainer(RAbstractDoubleVector x) { - int len = x.getLength(); - for (int i = 0; i < len; i++) { - if (RRuntime.isNA(x.getDataAt(i))) { - return handleNA(x); + @Specialization(guards = {"access.supports(x)", "!x.isComplete()"}) + protected RAbstractAtomicVector onPossiblyIncompleteContainerCached(RAbstractAtomicVector x, + @Cached("x.access()") VectorAccess access) { + try (SequentialIterator iter = access.access(x)) { + while (access.next(iter)) { + if (access.isNA(iter)) { + handleNA(x); + } } } return x; } - @Specialization(guards = "!isComplete(x)") - protected Object onPossiblyIncompleteContainer(RAbstractComplexVector x) { - int len = x.getLength(); - for (int i = 0; i < len; i++) { - if (RRuntime.isNA(x.getDataAt(i))) { - return handleNA(x); - } - } - return x; - } - - @Specialization(guards = "!isComplete(x)") - protected Object onPossiblyIncompleteContainer(RAbstractStringVector x) { - int len = x.getLength(); - for (int i = 0; i < len; i++) { - if (RRuntime.isNA(x.getDataAt(i))) { - return handleNA(x); - } - } - return x; - } - - @Specialization(guards = "!isComplete(x)") - protected Object onPossiblyIncompleteContainer(RAbstractRawVector x) { - return x; + @Specialization(replaces = "onPossiblyIncompleteContainerCached", guards = "!x.isComplete()") + protected RAbstractAtomicVector onPossiblyIncompleteContainerGeneric(RAbstractAtomicVector x) { + return onPossiblyIncompleteContainerCached(x, x.slowPathAccess()); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java index f830844351297e068af382b916b06b6a54c60932..83ddb43115f9529903a56305eee5b6cf7e65a8b7 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java @@ -1,97 +1,70 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This material is distributed under the GNU General Public License + * Version 2. You may review the terms of this license at + * http://www.gnu.org/licenses/gpl-2.0.html * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. + * Copyright (c) 2000-2013, The R Core Team + * Copyright (c) 2017, Oracle and/or its affiliates * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. + * All rights reserved. */ package com.oracle.truffle.r.nodes.unary; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.Arrays; - -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.nodes.SetDataAt; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.RandomIterator; +@ImportStatic(RRuntime.class) public abstract class SizeToOctalRawNode extends UnaryNode { - private Charset asciiCharset; + @Child private VectorFactory factory = VectorFactory.create(); + @Child private VectorAccess resultAccess = VectorAccess.createNew(RType.Raw); public abstract RRawVector execute(Object size); - @Specialization - protected RRawVector doInt(int s) { - return RDataFactory.createRawVector(toOctalAsciiString(s)); - } - - @TruffleBoundary - private byte[] toOctalAsciiString(int s) { - if (asciiCharset == null) { - asciiCharset = Charset.forName("US-ASCII"); + @Specialization(guards = "!isNA(size)") + protected RRawVector doInt(int size) { + if (size < 0) { + throw RError.error(RError.SHOW_CALLER, RError.Message.GENERIC, "size must be finite, >= 0 and < 2^33"); } - - ByteBuffer encode = asciiCharset.encode(Integer.toOctalString(s)); - // reverse - byte[] result = new byte[11]; - Arrays.fill(result, (byte) '0'); - for (int i = result.length - 1; i >= 0 && encode.hasRemaining(); i--) { - result[i] = encode.get(); - } - return result; + return toOctal(size); } // Transcribed from ".../utils/src/stubs.c" - @Specialization - protected RRawVector doDouble(double size, - @Cached("create()") SetDataAt.Raw setDataNode) { - - double s = size; - if (!RRuntime.isFinite(s) && s >= 0) { - throw RError.error(RError.SHOW_CALLER, RError.Message.GENERIC, "size must be finite and >= 0"); + @Specialization(guards = "!isNAorNaN(size)") + protected RRawVector doDouble(double size) { + if (!RRuntime.isFinite(size) || size < 0 || size >= 8589934592d /* 2^33 */) { + throw RError.error(RError.SHOW_CALLER, RError.Message.GENERIC, "size must be finite, >= 0 and < 2^33"); } + return toOctal((long) size); + } - RRawVector ans = RDataFactory.createRawVector(11); - byte[] store = ans.getInternalStore(); - - for (int i = 0; i < 11; i++) { - double s2 = Math.floor(s / 8.0); - double t = s - 8.0 * s2; - s = s2; - setDataNode.setDataAtAsObject(ans, store, 10 - i, (byte) (48.0 + t)); + private RRawVector toOctal(long size) { + RRawVector ans = factory.createRawVector(11); + try (RandomIterator iter = resultAccess.randomAccess(ans)) { + long s = size; + for (int i = 0; i < 11; i++) { + resultAccess.setRaw(iter, 10 - i, (byte) (48.0 + (s % 8))); + s /= 8; + } } return ans; } - @Specialization - protected RRawVector doNull(@SuppressWarnings("unused") RNull n) { + @Fallback + protected RRawVector doNull(@SuppressWarnings("unused") Object obj) { return RDataFactory.createRawVector(11); } public static SizeToOctalRawNode create() { return SizeToOctalRawNodeGen.create(); - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java index c28ada80ed370031b7657b128b183e7cf7036423..1aeae5ca87339c86ee0b1af963f6c76d19de0bb5 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/ToStringNode.java @@ -22,7 +22,8 @@ */ package com.oracle.truffle.r.nodes.unary; -import com.oracle.truffle.api.CompilerAsserts; +import java.util.EnumMap; + import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; @@ -32,23 +33,19 @@ import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.function.ClassHierarchyNode; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.Utils; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RFunction; -import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RS4Object; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; import com.oracle.truffle.r.runtime.data.RTypes; -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.RAbstractListVector; 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; import com.oracle.truffle.r.runtime.ops.na.NACheck; @@ -60,72 +57,58 @@ public abstract class ToStringNode extends RBaseNode { @Child private ToStringNode recursiveToString; - private final ConditionProfile isCachedIntProfile = ConditionProfile.createBinaryProfile(); - private final NACheck naCheck = NACheck.create(); - - private String toStringRecursive(Object o, boolean quotes, String separator) { + private String toStringRecursive(Object o, String separator) { if (recursiveToString == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); recursiveToString = insert(ToStringNodeGen.create()); } - return recursiveToString.executeString(o, quotes, separator); + return recursiveToString.executeString(o, separator); } - public abstract String executeString(Object o, boolean quotes, String separator); + public abstract String executeString(Object o, String separator); - @SuppressWarnings("unused") @Specialization - protected String toString(String value, boolean quotes, String separator) { - if (RRuntime.isNA(value)) { - return value; - } - if (quotes) { - return RRuntime.escapeString(value, false, true); - } + protected String toString(String value, @SuppressWarnings("unused") String separator) { return value; } - @SuppressWarnings("unused") @Specialization - protected String toString(RNull vector, boolean quotes, String separator) { + protected String toString(@SuppressWarnings("unused") RNull vector, @SuppressWarnings("unused") String separator) { return "NULL"; } - @SuppressWarnings("unused") @Specialization - protected String toString(RFunction function, boolean quotes, String separator) { + protected String toString(RFunction function, @SuppressWarnings("unused") String separator) { return RRuntime.toString(function); } - @SuppressWarnings("unused") @Specialization - protected String toString(RSymbol symbol, boolean quotes, String separator) { + protected String toString(RSymbol symbol, @SuppressWarnings("unused") String separator) { return symbol.getName(); } - @SuppressWarnings("unused") @Specialization - protected String toString(RComplex complex, boolean quotes, String separator) { + protected String toString(RComplex complex, @SuppressWarnings("unused") String separator, + @Cached("create()") NACheck naCheck) { naCheck.enable(complex); return naCheck.convertComplexToString(complex); } - @SuppressWarnings("unused") @Specialization - protected String toString(RRaw raw, boolean quotes, String separator) { + protected String toString(RRaw raw, @SuppressWarnings("unused") String separator) { return RRuntime.rawToHexString(raw.getValue()); } - @SuppressWarnings("unused") @Specialization - protected String toString(int operand, boolean quotes, String separator) { + protected String toString(int operand, @SuppressWarnings("unused") String separator) { return RRuntime.intToString(operand); } - @SuppressWarnings("unused") @Specialization - protected String toString(double operand, boolean quotes, String separator) { + protected String toString(double operand, @SuppressWarnings("unused") String separator, + @Cached("createBinaryProfile()") ConditionProfile isCachedIntProfile, + @Cached("create()") NACheck naCheck) { int intValue = (int) operand; if (isCachedIntProfile.profile(intValue == operand && RRuntime.isCachedNumberString(intValue))) { return RRuntime.getCachedNumberString(intValue); @@ -134,104 +117,84 @@ public abstract class ToStringNode extends RBaseNode { return naCheck.convertDoubleToString(operand); } - @SuppressWarnings("unused") @Specialization - protected String toString(byte operand, boolean quotes, String separator) { + protected String toString(byte operand, @SuppressWarnings("unused") String separator) { return RRuntime.logicalToString(operand); } @Specialization - protected String toString(RS4Object obj, @SuppressWarnings("unused") boolean quotes, String separator, - @Cached(value = "createWithImplicit()") ClassHierarchyNode hierarchy) { + @TruffleBoundary + protected String toString(RS4Object obj, @SuppressWarnings("unused") String separator, + @Cached("createWithImplicit()") ClassHierarchyNode hierarchy) { RStringVector classHierarchy = hierarchy.execute(obj); - Object clazz; - if (classHierarchy.getLength() > 0) { - clazz = toString(classHierarchy.getDataAt(0), true, separator); - } else { + if (classHierarchy.getLength() == 0) { throw RInternalError.shouldNotReachHere("S4 object has no class"); } - return Utils.stringFormat("<S4 object of class %s>", clazz); + return "<S4 object of class \"" + classHierarchy.getDataAt(0) + "\">"; } - @FunctionalInterface - private interface ElementFunction { - String apply(int index, boolean quotes, String separator); - } + private static final EnumMap<RType, String> EMPTY = new EnumMap<>(RType.class); - private static String createResultForVector(RAbstractVector vector, boolean quotes, String separator, String empty, ElementFunction elementFunction) { - CompilerAsserts.neverPartOfCompilation(); - int length = vector.getLength(); - if (length == 0) { - return empty; - } - StringBuilder b = new StringBuilder(); - for (int i = 0; i < length; i++) { - if (i > 0) { - b.append(separator); - } - b.append(elementFunction.apply(i, quotes, separator)); - } - return b.toString(); + static { + EMPTY.put(RType.Integer, "integer(0)"); + EMPTY.put(RType.Double, "numeric(0)"); + EMPTY.put(RType.Character, "character(0)"); + EMPTY.put(RType.Logical, "logical(0)"); + EMPTY.put(RType.Raw, "raw(0)"); + EMPTY.put(RType.Complex, "complex(0)"); + EMPTY.put(RType.List, "list()"); } - @Specialization - @TruffleBoundary - protected String toString(RAbstractIntVector vector, boolean quotes, String separator) { - return createResultForVector(vector, quotes, separator, "integer(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s)); - } - - @Specialization @TruffleBoundary - protected String toString(RAbstractDoubleVector vector, boolean quotes, String separator) { - return createResultForVector(vector, quotes, separator, "numeric(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s)); - } - - @Specialization - @TruffleBoundary - protected String toString(RAbstractStringVector vector, boolean quotes, String separator) { - return createResultForVector(vector, quotes, separator, "character(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s)); - } - - @Specialization - @TruffleBoundary - protected String toString(RAbstractLogicalVector vector, boolean quotes, String separator) { - return createResultForVector(vector, quotes, separator, "logical(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s)); - } - - @Specialization - @TruffleBoundary - protected String toString(RAbstractRawVector vector, boolean quotes, String separator) { - return createResultForVector(vector, quotes, separator, "raw(0)", (index, q, s) -> RRuntime.rawToHexString(vector.getRawDataAt(index))); + private String vectorToString(RAbstractVector vector, String separator, VectorAccess vectorAccess) { + try (SequentialIterator iter = vectorAccess.access(vector)) { + int length = vectorAccess.getLength(iter); + if (length == 0) { + return EMPTY.get(vectorAccess.getType()); + } + StringBuilder b = new StringBuilder(); + if (vectorAccess.next(iter)) { + while (true) { + if (vectorAccess.getType() == RType.List) { + Object value = vectorAccess.getListElement(iter); + if (value instanceof RAbstractListVector) { + RAbstractListVector l = (RAbstractListVector) value; + if (l.getLength() == 0) { + b.append("list()"); + } else { + b.append("list(").append(toStringRecursive(l, separator)).append(')'); + } + } else { + b.append(toStringRecursive(value, separator)); + } + } else { + b.append(vectorAccess.getString(iter)); + } + if (!vectorAccess.next(iter)) { + break; + } + b.append(separator); + } + } + return b.toString(); + } } - @Specialization - @TruffleBoundary - protected String toString(RAbstractComplexVector vector, boolean quotes, String separator) { - return createResultForVector(vector, quotes, separator, "complex(0)", (index, q, s) -> toString(vector.getDataAt(index), q, s)); + @Specialization(guards = "vectorAccess.supports(vector)") + protected String toStringVectorCached(RAbstractVector vector, String separator, + @Cached("vector.access()") VectorAccess vectorAccess) { + return vectorToString(vector, separator, vectorAccess); } - @Specialization - @TruffleBoundary - protected String toString(RList vector, boolean quotes, String separator) { - return createResultForVector(vector, quotes, separator, "list()", (index, q, s) -> { - Object value = vector.getDataAt(index); - if (value instanceof RList) { - RList l = (RList) value; - if (l.getLength() == 0) { - return "list()"; - } else { - return "list(" + toStringRecursive(l, q, s) + ')'; - } - } else { - return toStringRecursive(value, q, s); - } - }); + @Specialization(replaces = "toStringVectorCached") + protected String toStringVectorGeneric(RAbstractVector vector, String separator) { + return vectorToString(vector, separator, vector.slowPathAccess()); } @SuppressWarnings("unused") @Specialization @TruffleBoundary - protected String toString(REnvironment env, boolean quotes, String separator) { + protected String toString(REnvironment env, String separator) { return env.toString(); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java index 1f0892d7285603e2bf2950d8ba38a5b7df910ed3..170ac15bf2741ef642c1e946b024fe507c27fd92 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticNode.java @@ -52,42 +52,45 @@ public abstract class UnaryArithmeticNode extends UnaryNode { public abstract Object execute(Object value); @Specialization(guards = {"cachedNode != null", "cachedNode.isSupported(operand)"}) - protected Object doCached(Object operand, + protected Object doCached(RAbstractVector operand, @Cached("createCachedFast(operand)") UnaryMapNode cachedNode) { return cachedNode.apply(operand); } - protected UnaryMapNode createCachedFast(Object operand) { + protected UnaryMapNode createCachedFast(RAbstractVector operand) { if (isNumericVector(operand)) { - return createCached(unary.createOperation(), operand); + return createCached(unary.createOperation(), operand, false); } return null; } - protected static UnaryMapNode createCached(UnaryArithmetic arithmetic, Object operand) { + protected static UnaryMapNode createCached(UnaryArithmetic arithmetic, Object operand, boolean isGeneric) { if (operand instanceof RAbstractVector) { RAbstractVector castOperand = (RAbstractVector) operand; RType operandType = castOperand.getRType(); if (operandType.isNumeric()) { RType type = RType.maxPrecedence(operandType, arithmetic.getMinPrecedence()); RType resultType = arithmetic.calculateResultType(type); - return UnaryMapNode.create(new ScalarUnaryArithmeticNode(arithmetic), castOperand, type, resultType); + return UnaryMapNode.create(new ScalarUnaryArithmeticNode(arithmetic), castOperand, type, resultType, isGeneric); } } return null; } - protected static boolean isNumericVector(Object value) { + protected static boolean isNumericVector(RAbstractVector value) { return value instanceof RAbstractIntVector || value instanceof RAbstractDoubleVector || value instanceof RAbstractComplexVector || value instanceof RAbstractLogicalVector; } @Specialization(replaces = "doCached", guards = {"isNumericVector(operand)"}) @TruffleBoundary - protected Object doGeneric(Object operand, + protected Object doGeneric(RAbstractVector operand, @Cached("unary.createOperation()") UnaryArithmetic arithmetic, - @Cached("new(createCached(arithmetic, operand))") GenericNumericVectorNode generic) { - RAbstractVector operandVector = (RAbstractVector) operand; - return generic.get(arithmetic, operandVector).apply(operandVector); + @Cached("createGeneric()") GenericNumericVectorNode generic) { + return generic.get(arithmetic, operand).apply(operand); + } + + protected static GenericNumericVectorNode createGeneric() { + return new GenericNumericVectorNode(); } @Override @@ -110,16 +113,12 @@ public abstract class UnaryArithmeticNode extends UnaryNode { @Child private UnaryMapNode cached; - public GenericNumericVectorNode(UnaryMapNode cachedOperation) { - this.cached = cachedOperation; - } - public UnaryMapNode get(UnaryArithmetic arithmetic, RAbstractVector operand) { - UnaryMapNode next = cached; - if (!next.isSupported(operand)) { - next = cached.replace(createCached(arithmetic, operand)); + UnaryMapNode map = cached; + if (map == null || !map.isSupported(operand)) { + cached = map = insert(createCached(arithmetic, operand, true)); } - return next; + return map; } } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java index 4f2f375192eb681092cf8f87eef33ad04c367e80..7230d7b17e60bd571680b3792d0dc235d8562e0c 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryArithmeticReduceNode.java @@ -22,17 +22,17 @@ */ package com.oracle.truffle.r.nodes.unary; -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.dsl.TypeSystemReference; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; -import com.oracle.truffle.r.nodes.control.RLengthNode; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RComplexVector; @@ -42,8 +42,8 @@ import com.oracle.truffle.r.runtime.data.RTypes; 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.nodes.EnableNACheckNode; -import com.oracle.truffle.r.runtime.data.nodes.VectorIterator; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.interop.ForeignArray2R; import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.ops.BinaryArithmetic; @@ -57,6 +57,8 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck; * only applies to some types (e.g. double or integer), for other types 'finite' seems to be ignored * (e.g. logical). The only situation where semantics of finite is different to na.rm is double * values: na.rm removes NA and NaN, but not -/+Inf. + * + * FastR handles finite consistently (setting na.rm = TRUE if finite = TRUE) in the range builtin. */ @ImportStatic({RRuntime.class}) @TypeSystemReference(RTypes.class) @@ -64,7 +66,6 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { public abstract Object executeReduce(Object value, boolean naRm, boolean finite); - @Child private MultiElemStringHandlerNode stringHandler; @Child private BinaryArithmetic arithmetic; private final BinaryArithmeticFactory factory; @@ -74,6 +75,8 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { private final NACheck na = NACheck.create(); private final ConditionProfile naRmProfile = ConditionProfile.createBinaryProfile(); + private final BranchProfile emptyProfile = BranchProfile.create(); + private final BranchProfile naResultProfile = BranchProfile.create(); protected UnaryArithmeticReduceNode(ReduceSemantics semantics, BinaryArithmeticFactory factory) { this.factory = factory; @@ -83,21 +86,15 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { this.supportComplex = semantics.supportComplex; } - private String handleString(RStringVector operand, boolean naRm, boolean finite, int offset) { - if (stringHandler == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - stringHandler = insert(new MultiElemStringHandlerNode(semantics, factory, na)); - } - return stringHandler.executeString(operand, naRm, finite, offset); - } - private void emptyWarning() { + emptyProfile.enter(); if (semantics.getEmptyWarning() != null) { warning(semantics.emptyWarning); } } private void naResultWarning() { + naResultProfile.enter(); if (semantics.getNAResultWarning() != null) { warning(semantics.getNAResultWarning()); } @@ -136,20 +133,23 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { protected double doDouble(double operand, boolean naRm, boolean finite, @Cached("createBinaryProfile()") ConditionProfile finiteProfile, @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) { + if (finiteProfile.profile(finite) && isInfiniteProfile.profile(!RRuntime.isFinite(operand))) { + emptyWarning(); + return semantics.getIntStart(); + } na.enable(operand); - if (naRmProfile.profile(naRm || finite)) { - boolean profiledFinite = finiteProfile.profile(finite); - if (na.checkNAorNaN(operand) || (profiledFinite && isInfiniteProfile.profile(!RRuntime.isFinite(operand)))) { + if (naRmProfile.profile(naRm)) { + if (na.checkNAorNaN(operand)) { // the only value we have should be removed... emptyWarning(); return semantics.getIntStart(); } else { + // known not to be NA or NaN return operand; } - } else { - // since !naRm and !finite, NaN or +/-Inf can be valid results - return na.check(operand) ? RRuntime.DOUBLE_NA : operand; } + // since !naRm and !finite, NaN or +/-Inf can be valid results + return na.check(operand) ? RRuntime.DOUBLE_NA : operand; } @Specialization @@ -199,35 +199,47 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { } } - @Specialization - protected Object doIntVector(RAbstractIntVector operand, boolean naRm, boolean finite, - @Cached("create()") EnableNACheckNode enableNACheckNode, - @Cached("create()") RLengthNode lengthNode, - @Cached("create()") VectorIterator.Int iterator) { - RBaseNode.reportWork(this, lengthNode.executeInteger(operand)); - boolean profiledNaRm = naRmProfile.profile(naRm || finite); + private Object doInt(RAbstractVector vector, boolean naRm, VectorAccess access) { + boolean profiledNaRm = naRmProfile.profile(naRm); int result = semantics.getIntStart(); - enableNACheckNode.execute(na, operand); - int opCount = 0; - Object it = iterator.init(operand); - while (iterator.hasNext(operand, it)) { - int d = iterator.next(operand, it); - if (na.check(d)) { - if (profiledNaRm) { - continue; - } else { - return RRuntime.INT_NA; + boolean empty = true; + try (VectorAccess.SequentialIterator iter = access.access(vector)) { + while (access.next(iter)) { + int d; + switch (access.getType()) { + case Integer: + d = access.getInt(iter); + if (access.na.check(d)) { + if (profiledNaRm) { + continue; + } else { + return RRuntime.INT_NA; + } + } + break; + case Logical: + byte logical = access.getLogical(iter); + if (access.na.check(logical)) { + if (profiledNaRm) { + continue; + } else { + return RRuntime.INT_NA; + } + } + d = logical; // 0 or 1 + break; + default: + throw RInternalError.shouldNotReachHere(); } - } else { result = arithmetic.op(result, d); if (RRuntime.isNA(result)) { naResultWarning(); return RRuntime.INT_NA; } + empty = false; } - opCount++; } - if (opCount == 0) { + if (empty) { emptyWarning(); if (semantics.isUseDoubleStartForEmptyVector()) { return semantics.getDoubleStart(); @@ -236,88 +248,79 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { return result; } - @Specialization - protected double doDoubleVector(RAbstractDoubleVector operand, boolean naRm, boolean finite, - @Cached("create()") EnableNACheckNode enableNACheckNode, - @Cached("create()") RLengthNode lengthNode, - @Cached("create()") VectorIterator.Double iterator, - @Cached("createBinaryProfile()") ConditionProfile finiteProfile, - @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) { - RBaseNode.reportWork(this, lengthNode.executeInteger(operand)); - boolean profiledNaRm = naRmProfile.profile(naRm || finite); - boolean profiledFinite = finiteProfile.profile(finite); - double result = semantics.getDoubleStart(); - enableNACheckNode.execute(na, operand); - int opCount = 0; + @Specialization(guards = "access.supports(vector)") + protected Object doIntCached(RAbstractIntVector vector, boolean naRm, @SuppressWarnings("unused") boolean finite, + @Cached("vector.access()") VectorAccess access) { + return doInt(vector, naRm, access); + } - Object it = iterator.init(operand); - while (iterator.hasNext(operand, it)) { - double d = iterator.next(operand, it); - if (na.checkNAorNaN(d)) { - if (profiledNaRm) { - continue; // ignore NA/NaN - } else if (na.check(d)) { - // NA produces NA directly, but NaN should be handled by arithmetics.op to - // produce NaN. We cannot directly return NaN because if we encounter NA later - // on, we should return NA not NaN - return RRuntime.DOUBLE_NA; - } - } else if (profiledFinite && isInfiniteProfile.profile(!RRuntime.isFinite(d))) { - // ignore -/+Inf if 'infinite == TRUE' - continue; - } + @Specialization(replaces = "doIntCached") + protected Object doIntGeneric(RAbstractIntVector vector, boolean naRm, @SuppressWarnings("unused") boolean finite) { + return doInt(vector, naRm, vector.slowPathAccess()); + } - result = arithmetic.op(result, d); - opCount++; - } - if (opCount == 0) { - emptyWarning(); - } - return result; + @Specialization(guards = "access.supports(vector)") + protected Object doLogicalCached(RAbstractLogicalVector vector, boolean naRm, @SuppressWarnings("unused") boolean finite, + @Cached("vector.access()") VectorAccess access) { + return doInt(vector, naRm, access); } - @Specialization - protected Object doLogicalVector(RAbstractLogicalVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite, - @Cached("create()") EnableNACheckNode enableNACheckNode, - @Cached("create()") RLengthNode lengthNode, - @Cached("create()") VectorIterator.Logical iterator) { - RBaseNode.reportWork(this, lengthNode.executeInteger(operand)); - boolean profiledNaRm = naRmProfile.profile(naRm); - int result = semantics.getIntStart(); - enableNACheckNode.execute(na, operand); - int opCount = 0; + @Specialization(replaces = "doIntCached") + protected Object doLogicalGeneric(RAbstractLogicalVector vector, boolean naRm, @SuppressWarnings("unused") boolean finite) { + return doInt(vector, naRm, vector.slowPathAccess()); + } - Object it = iterator.init(operand); - while (iterator.hasNext(operand, it)) { - byte d = iterator.next(operand, it); - if (na.check(d)) { - if (profiledNaRm) { + private double doDouble(RAbstractDoubleVector vector, boolean naRm, boolean finite, ConditionProfile finiteProfile, ConditionProfile isInfiniteProfile, VectorAccess access) { + boolean profiledNaRm = naRmProfile.profile(naRm); + boolean profiledFinite = finiteProfile.profile(finite); + double result = semantics.getDoubleStart(); + boolean empty = true; + try (VectorAccess.SequentialIterator iter = access.access(vector)) { + while (access.next(iter)) { + double d = access.getDouble(iter); + if (access.na.checkNAorNaN(d)) { + if (profiledNaRm) { + continue; // ignore NA/NaN + } else if (access.na.check(d)) { + // NA produces NA directly, but NaN should be handled by arithmetics.op to + // produce NaN. We cannot directly return NaN because if we encounter NA + // later + // on, we should return NA not NaN + return RRuntime.DOUBLE_NA; + } + } else if (profiledFinite && isInfiniteProfile.profile(!RRuntime.isFinite(d))) { + // ignore -/+Inf if 'infinite == TRUE' continue; - } else { - return RRuntime.INT_NA; } - } else { result = arithmetic.op(result, d); - if (RRuntime.isNA(result)) { - naResultWarning(); - return RRuntime.INT_NA; - } + empty = false; } - opCount++; } - if (opCount == 0) { + if (empty) { emptyWarning(); - if (semantics.isUseDoubleStartForEmptyVector()) { - return semantics.getDoubleStart(); - } } return result; } + @Specialization(guards = "access.supports(vector)") + protected double doDoubleCached(RAbstractDoubleVector vector, boolean naRm, boolean finite, + @Cached("createBinaryProfile()") ConditionProfile finiteProfile, + @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile, + @Cached("vector.access()") VectorAccess access) { + return doDouble(vector, naRm, finite, finiteProfile, isInfiniteProfile, access); + } + + @Specialization(replaces = "doDoubleCached") + protected double doDoubleGeneric(RAbstractDoubleVector vector, boolean naRm, boolean finite, + @Cached("createBinaryProfile()") ConditionProfile finiteProfile, + @Cached("createBinaryProfile()") ConditionProfile isInfiniteProfile) { + return doDouble(vector, naRm, finite, finiteProfile, isInfiniteProfile, vector.slowPathAccess()); + } + @Specialization(guards = "supportComplex") - protected RComplex doComplexVector(RComplexVector operand, boolean naRm, boolean finite) { + protected RComplex doComplexVector(RComplexVector operand, boolean naRm, @SuppressWarnings("unused") boolean finite) { RBaseNode.reportWork(this, operand.getLength()); - boolean profiledNaRm = naRmProfile.profile(naRm || finite); + boolean profiledNaRm = naRmProfile.profile(naRm); RComplex result = RRuntime.double2complex(semantics.getDoubleStart()); int opCount = 0; na.enable(operand); @@ -344,18 +347,14 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { // does not work for String-s as, in particular, we cannot supply the (lexicographically) // "largest" String for the implementation of max function - private static String doStringVectorEmptyInternal(ReduceSemantics semantics, RBaseNode invokingNode) { + @Specialization(guards = {"supportString", "operand.getLength() == 0"}) + protected String doStringVectorEmpty(@SuppressWarnings("unused") RStringVector operand, @SuppressWarnings("unused") boolean naRm, @SuppressWarnings("unused") boolean finite) { if (semantics.getEmptyWarning() != null) { - RError.warning(invokingNode, semantics.emptyWarningCharacter); + warning(semantics.emptyWarningCharacter); } return semantics.getStringStart(); } - @Specialization(guards = {"supportString", "operand.getLength() == 0"}) - protected String doStringVectorEmpty(@SuppressWarnings("unused") RStringVector operand, @SuppressWarnings("unused") boolean naRm, @SuppressWarnings("unused") boolean finite) { - return doStringVectorEmptyInternal(semantics, this); - } - @Specialization(guards = {"supportString", "operand.getLength() == 1"}) protected String doStringVectorOneElem(RStringVector operand, boolean naRm, boolean finite) { boolean profiledNaRm = naRmProfile.profile(naRm); @@ -371,7 +370,40 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { @Specialization(guards = {"supportString", "operand.getLength() > 1"}) protected String doStringVector(RStringVector operand, boolean naRm, boolean finite) { - return handleString(operand, naRm, finite, 0); + boolean profiledNaRm = naRmProfile.profile(naRm); + na.enable(operand); + int offset = 0; + String result = operand.getDataAt(offset); + if (profiledNaRm) { + while (na.check(result)) { + // the following is meant to eliminate leading NA-s + if (offset == operand.getLength() - 1) { + // last element - all other are NAs + return doStringVectorEmpty(operand, naRm, finite); + } + result = operand.getDataAt(++offset); + } + } else { + if (na.check(result)) { + return result; + } + } + // when we reach here, it means that we have already seen one non-NA element + assert !RRuntime.isNA(result); + for (int i = offset + 1; i < operand.getLength(); i++) { + String current = operand.getDataAt(i); + if (na.check(current)) { + if (profiledNaRm) { + // skip NA-s + continue; + } else { + return RRuntime.STRING_NA; + } + } else { + result = arithmetic.op(result, current); + } + } + return result; } @Specialization(guards = {"isForeignObject(obj)"}) @@ -452,67 +484,4 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { return useDoubleStartForEmptyVector; } } - - private static final class MultiElemStringHandlerNode extends RBaseNode { - - @Child private MultiElemStringHandlerNode recursiveStringHandler; - @Child private BinaryArithmetic arithmetic; - - private final ReduceSemantics semantics; - private final BinaryArithmeticFactory factory; - private final NACheck na; - private final ConditionProfile naRmProfile = ConditionProfile.createBinaryProfile(); - - MultiElemStringHandlerNode(ReduceSemantics semantics, BinaryArithmeticFactory factory, NACheck na) { - this.semantics = semantics; - this.factory = factory; - this.arithmetic = factory.createOperation(); - this.na = na; - } - - private String handleString(RStringVector operand, boolean naRm, boolean finite, int offset) { - if (recursiveStringHandler == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - recursiveStringHandler = insert(new MultiElemStringHandlerNode(semantics, factory, na)); - } - return recursiveStringHandler.executeString(operand, naRm, finite, offset); - } - - public String executeString(RStringVector operand, boolean naRm, boolean finite, int offset) { - boolean profiledNaRm = naRmProfile.profile(naRm); - na.enable(operand); - String result = operand.getDataAt(offset); - if (profiledNaRm) { - if (na.check(result)) { - // the following is meant to eliminate leading NA-s - if (offset == operand.getLength() - 1) { - // last element - all other are NAs - return doStringVectorEmptyInternal(semantics, this); - } else { - return handleString(operand, naRm, finite, offset + 1); - } - } - } else { - if (na.check(result)) { - return result; - } - } - // when we reach here, it means that we have already seen one non-NA element - assert !RRuntime.isNA(result); - for (int i = offset + 1; i < operand.getLength(); i++) { - String current = operand.getDataAt(i); - if (na.check(current)) { - if (profiledNaRm) { - // skip NA-s - continue; - } else { - return RRuntime.STRING_NA; - } - } else { - result = arithmetic.op(result, current); - } - } - return result; - } - } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java index acd72feaf1484c0c8e4a36165d7538c523617628..1ee0499aa4ace76f7fa3e2b83eadb38ac6d32d38 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/UnaryNotNode.java @@ -32,34 +32,37 @@ import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.Message; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimNamesAttributeNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.builtins.RBuiltin; -import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RLogicalVector; +import com.oracle.truffle.r.runtime.data.RDataFactory.VectorFactory; import com.oracle.truffle.r.runtime.data.RRaw; -import com.oracle.truffle.r.runtime.data.RRawVector; -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.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.RVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; 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.data.nodes.VectorReuse; import com.oracle.truffle.r.runtime.interop.ForeignArray2R; -import com.oracle.truffle.r.runtime.ops.na.NACheck; import com.oracle.truffle.r.runtime.ops.na.NAProfile; -@ImportStatic({RRuntime.class}) +@ImportStatic({RRuntime.class, ForeignArray2R.class, Message.class, RType.class}) @RBuiltin(name = "!", kind = PRIMITIVE, parameterNames = {""}, dispatch = OPS_GROUP_GENERIC, behavior = PURE_ARITHMETIC) public abstract class UnaryNotNode extends RBuiltinNode.Arg1 { - private final NACheck na = NACheck.create(); private final NAProfile naProfile = NAProfile.create(); - private final ConditionProfile zeroLengthProfile = ConditionProfile.createBinaryProfile(); + + @Child private GetDimAttributeNode getDims = GetDimAttributeNode.create(); + @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create(); + @Child private GetDimNamesAttributeNode getDimNames = GetDimNamesAttributeNode.create(); static { Casts.noCasts(UnaryNotNode.class); @@ -77,10 +80,6 @@ public abstract class UnaryNotNode extends RBuiltinNode.Arg1 { return RRuntime.asLogical(operand == 0); } - private static byte not(RComplex operand) { - return RRuntime.asLogical(operand.getRealPart() == 0 && operand.getImaginaryPart() == 0); - } - private static byte notRaw(RRaw operand) { return notRaw(operand.getValue()); } @@ -109,112 +108,83 @@ public abstract class UnaryNotNode extends RBuiltinNode.Arg1 { return RDataFactory.createRaw(notRaw(operand)); } - @Specialization - protected RLogicalVector doLogicalVector(RLogicalVector vector) { - int length = vector.getLength(); - byte[] result; - if (zeroLengthProfile.profile(length == 0)) { - result = new byte[0]; - } else { - na.enable(vector); - result = new byte[length]; - for (int i = 0; i < length; i++) { - byte value = vector.getDataAt(i); - result[i] = na.check(value) ? RRuntime.LOGICAL_NA : not(value); + @Specialization(guards = {"vectorAccess.supports(vector)", "reuse.supports(vector)"}) + protected RAbstractVector doLogicalVectorCached(RAbstractLogicalVector vector, + @Cached("vector.access()") VectorAccess vectorAccess, + @Cached("createTemporary(vector)") VectorReuse reuse) { + RAbstractVector result = reuse.getResult(vector); + VectorAccess resultAccess = reuse.access(result); + try (SequentialIterator vectorIter = vectorAccess.access(vector); SequentialIterator resultIter = resultAccess.access(result)) { + while (vectorAccess.next(vectorIter) && resultAccess.next(resultIter)) { + byte value = vectorAccess.getLogical(vectorIter); + resultAccess.setLogical(resultIter, vectorAccess.na.check(value) ? RRuntime.LOGICAL_NA : not(value)); } } - RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA()); - resultVector.copyAttributesFrom(vector); - return resultVector; - } - - @Specialization - protected RLogicalVector doIntVector(RAbstractIntVector vector) { - int length = vector.getLength(); - byte[] result; - if (zeroLengthProfile.profile(length == 0)) { - result = new byte[0]; - } else { - na.enable(vector); - result = new byte[length]; - for (int i = 0; i < length; i++) { - int value = vector.getDataAt(i); - result[i] = na.check(value) ? RRuntime.LOGICAL_NA : not(value); - } - } - RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA()); - copyNamesDimsDimNames(vector, resultVector); - return resultVector; - } - - @Specialization - protected RLogicalVector doDoubleVector(RAbstractDoubleVector vector) { - int length = vector.getLength(); - byte[] result; - if (zeroLengthProfile.profile(length == 0)) { - result = new byte[0]; - } else { - na.enable(vector); - result = new byte[length]; - for (int i = 0; i < length; i++) { - double value = vector.getDataAt(i); - result[i] = na.check(value) ? RRuntime.LOGICAL_NA : not(value); - } - } - RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA()); - copyNamesDimsDimNames(vector, resultVector); - return resultVector; - } - - @Specialization - protected RLogicalVector doComplexVector(RAbstractComplexVector vector) { - int length = vector.getLength(); - byte[] result; - if (zeroLengthProfile.profile(length == 0)) { - result = new byte[0]; - } else { - na.enable(vector); - result = new byte[length]; - for (int i = 0; i < length; i++) { - RComplex value = vector.getDataAt(i); - result[i] = na.check(value) ? RRuntime.LOGICAL_NA : not(value); - } - } - RLogicalVector resultVector = RDataFactory.createLogicalVector(result, na.neverSeenNA()); - copyNamesDimsDimNames(vector, resultVector); - return resultVector; + result.setComplete(vectorAccess.na.neverSeenNA()); + return result; } + @Specialization(replaces = "doLogicalVectorCached") @TruffleBoundary - private void copyNamesDimsDimNames(RAbstractVector vector, RLogicalVector resultVector) { - resultVector.copyNamesDimsDimNamesFrom(vector, this); - } - - @Specialization - protected RRawVector doRawVector(RRawVector vector) { - int length = vector.getLength(); - byte[] result; - if (zeroLengthProfile.profile(length == 0)) { - result = new byte[0]; - } else { - result = new byte[length]; - for (int i = 0; i < length; i++) { - result[i] = notRaw(vector.getRawDataAt(i)); + protected RAbstractVector doLogicalGenericGeneric(RAbstractLogicalVector vector, + @Cached("createTemporaryGeneric()") VectorReuse reuse) { + return doLogicalVectorCached(vector, vector.slowPathAccess(), reuse); + } + + @Specialization(guards = {"vectorAccess.supports(vector)", "!isRAbstractLogicalVector(vector)"}) + protected RAbstractVector doVectorCached(RAbstractVector vector, + @Cached("vector.access()") VectorAccess vectorAccess, + @Cached("createNew(Logical)") VectorAccess resultAccess, + @Cached("createNew(Raw)") VectorAccess rawResultAccess, + @Cached("create()") VectorFactory factory) { + try (SequentialIterator vectorIter = vectorAccess.access(vector)) { + int length = vectorAccess.getLength(vectorIter); + RAbstractVector result; + switch (vectorAccess.getType()) { + case Character: + case List: + case Expression: + // special cases: + if (length == 0) { + return factory.createEmptyLogicalVector(); + } else { + throw error(RError.Message.INVALID_ARG_TYPE); + } + case Raw: + result = factory.createRawVector(length); + try (SequentialIterator resultIter = rawResultAccess.access(result)) { + // raw does not produce a logical result, but (255 - value) + while (vectorAccess.next(vectorIter) && rawResultAccess.next(resultIter)) { + rawResultAccess.setRaw(resultIter, notRaw(vectorAccess.getRaw(vectorIter))); + } + } + ((RVector<?>) result).copyAttributesFrom(vector); + break; + default: + result = factory.createLogicalVector(length, false); + try (SequentialIterator resultIter = resultAccess.access(result)) { + while (vectorAccess.next(vectorIter) && resultAccess.next(resultIter)) { + byte value = vectorAccess.getLogical(vectorIter); + resultAccess.setLogical(resultIter, vectorAccess.na.check(value) ? RRuntime.LOGICAL_NA : not(value)); + } + } + if (vectorAccess.getType() == RType.Logical) { + ((RVector<?>) result).copyAttributesFrom(vector); + } else { + factory.reinitializeAttributes((RVector<?>) result, getDims.getDimensions(vector), getNames.getNames(vector), getDimNames.getDimNames(vector)); + } + break; } + result.setComplete(vectorAccess.na.neverSeenNA()); + return result; } - RRawVector resultVector = RDataFactory.createRawVector(result); - resultVector.copyAttributesFrom(vector); - return resultVector; } - @Specialization(guards = {"vector.getLength() == 0"}) - protected RLogicalVector doStringVector(@SuppressWarnings("unused") RAbstractStringVector vector) { - return RDataFactory.createEmptyLogicalVector(); - } - - @Specialization(guards = {"list.getLength() == 0"}) - protected RLogicalVector doList(@SuppressWarnings("unused") RList list) { - return RDataFactory.createEmptyLogicalVector(); + @Specialization(replaces = "doVectorCached", guards = "!isRAbstractLogicalVector(vector)") + @TruffleBoundary + protected RAbstractVector doGenericGeneric(RAbstractVector vector, + @Cached("create()") VectorFactory factory) { + return doVectorCached(vector, vector.slowPathAccess(), VectorAccess.createSlowPathNew(RType.Logical), VectorAccess.createSlowPathNew(RType.Raw), factory); } @Specialization(guards = {"isForeignObject(obj)"}) diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java index 090cd5aa987d71ee1ac1da2c7155bc2e7643cdd2..5a9c503079500a97603e9ffdb595104feaa5314e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/FastROptions.java @@ -62,6 +62,7 @@ public enum FastROptions { EmitTmpHashed("Use an SHA-256 hash as file name to reduce temporary file creation.", true), SpawnUsesPolyglot("use PolyglotEngine for .fastr.context.spwan", false), SynchronizeNativeCode("allow only one thread to enter packages' native code", false), + ForeignObjectWrappers("use wrappers for foreign objects (as opposed to full conversion)", false), // Promises optimizations EagerEval("If enabled, overrides all other EagerEval switches (see EagerEvalHelper)", false), diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java index 2cc2e1bba7016ef1c6e6ac5ce4f6336a53f9ede4..d1962cdbda9885bcd08be41996fc7601e025e062 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java @@ -789,7 +789,7 @@ public class RErrorHandling { String preamble = kind; String errorMsg = null; assert call instanceof RNull || call instanceof RLanguage; - if (call == RNull.instance || ((RLanguage) call).getRep().getSourceSection() == null) { + if (call == RNull.instance) { // generally means top-level of shell or similar preamble += ": "; errorMsg = preamble + formattedMsg; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java index d3965fab24e62015dbb1b7fe3377b7ca5df88c39..b1bc38b64be0efeffb3e466b46e68d2618ff880c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java @@ -68,6 +68,10 @@ public class RRuntime { //@formatter:on + // used in DSL expressions: + public static final boolean True = true; + public static final boolean False = false; + public static final String R_APP_MIME = "application/x-r"; public static final String R_TEXT_MIME = "text/x-r"; @@ -352,11 +356,6 @@ public class RRuntime { return rawStringCache[raw2int(operand)]; } - @TruffleBoundary - public static String rawToString(byte operand) { - return intToString(raw2int(operand)); - } - // conversions from string @TruffleBoundary @@ -762,6 +761,10 @@ public class RRuntime { return isNA(value.getRealPart()) || isNA(value.getImaginaryPart()); } + public static boolean isNA(double real, double imag) { + return isNA(real) || isNA(imag); + } + @TruffleBoundary public static String escapeString(String value, boolean encodeNonASCII, boolean quote) { if (isNA(value)) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java index 3b5cda9b10a5638ac01ece23836d09c25780e9f6..33167db9996d17a6e913220a05b9681bd97fb8da 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSerialize.java @@ -53,10 +53,8 @@ import com.oracle.truffle.r.runtime.data.Closure; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributesLayout; -import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.REmpty; -import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RExternalPtr; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RLanguage; @@ -66,7 +64,6 @@ import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPairList; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RPromise.PromiseState; -import com.oracle.truffle.r.runtime.data.RRawVector; import com.oracle.truffle.r.runtime.data.RScalar; import com.oracle.truffle.r.runtime.data.RShareable; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -77,11 +74,14 @@ import com.oracle.truffle.r.runtime.data.RVector; 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.RAbstractListBaseVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; 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.env.frame.ActiveBinding; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; @@ -1262,10 +1262,8 @@ public class RSerialize { } } - // Serialize support is currently very limited, essentially to saving the CRAN package format - // info, - private abstract static class POutputStream { + protected OutputStream os; POutputStream(OutputStream os) { @@ -1278,7 +1276,7 @@ public class RSerialize { abstract void writeDouble(double value) throws IOException; - abstract void writeRaw(byte[] value) throws IOException; + abstract void writeRaw(byte value) throws IOException; abstract void flush() throws IOException; @@ -1339,16 +1337,9 @@ public class RSerialize { } @Override - void writeRaw(byte[] value) throws IOException { - int valueLen = value.length; - if (valueLen > buf.length) { - flushBuffer(); - os.write(value); - } else { - ensureSpace(valueLen); - System.arraycopy(value, 0, buf, offset, valueLen); - offset += valueLen; - } + void writeRaw(byte value) throws IOException { + ensureSpace(1); + buf[offset++] = value; } @Override @@ -1480,6 +1471,9 @@ public class RSerialize { Object obj = objArg; boolean tailCall; do { + // convert primitive types into RAbstractVectors + obj = RRuntime.asAbstractVector(obj); + tailCall = false; SEXPTYPE specialType; Object psn; @@ -1548,70 +1542,49 @@ public class RSerialize { stream.writeInt(flags); switch (type) { case STRSXP: { - if (obj instanceof String) { - // length 1 vector - stream.writeInt(1); - writeCHARSXP((String) obj); - } else { - outStringVec((RAbstractStringVector) obj, true); - } + outStringVec((RAbstractStringVector) obj, true); break; } - case INTSXP: { - if (obj instanceof Integer) { - stream.writeInt(1); - stream.writeInt((int) obj); - } else { - RAbstractIntVector vec = (RAbstractIntVector) obj; - stream.writeInt(vec.getLength()); - for (int i = 0; i < vec.getLength(); i++) { - stream.writeInt(vec.getDataAt(i)); + case INTSXP: + case LGLSXP: { + // logicals are written as ints + RAbstractVector vector = (RAbstractVector) obj; + VectorAccess access = vector.slowPathAccess(); + try (SequentialIterator iter = access.access(vector)) { + stream.writeInt(access.getLength(iter)); + while (access.next(iter)) { + stream.writeInt(access.getInt(iter)); } } break; } case REALSXP: { - if (obj instanceof Double) { - stream.writeInt(1); - stream.writeDouble((double) obj); - } else { - RAbstractDoubleVector vec = (RAbstractDoubleVector) obj; - stream.writeInt(vec.getLength()); - for (int i = 0; i < vec.getLength(); i++) { - stream.writeDouble(vec.getDataAt(i)); - } - } - break; - } - - case LGLSXP: { - // Output as ints - if (obj instanceof Byte) { - stream.writeInt(1); - stream.writeInt(RRuntime.logical2int((byte) obj)); - } else { - RAbstractLogicalVector vec = (RAbstractLogicalVector) obj; - stream.writeInt(vec.getLength()); - for (int i = 0; i < vec.getLength(); i++) { - stream.writeInt(RRuntime.logical2int(vec.getDataAt(i))); + RAbstractDoubleVector vector = (RAbstractDoubleVector) obj; + VectorAccess access = vector.slowPathAccess(); + try (SequentialIterator iter = access.access(vector)) { + stream.writeInt(access.getLength(iter)); + while (access.next(iter)) { + stream.writeDouble(access.getDouble(iter)); } } break; } case CPLXSXP: { - RAbstractComplexVector vec = (RAbstractComplexVector) obj; - stream.writeInt(vec.getLength()); - for (int i = 0; i < vec.getLength(); i++) { - RComplex val = vec.getDataAt(i); - if (RRuntime.isNA(val)) { - stream.writeDouble(RRuntime.DOUBLE_NA); - stream.writeDouble(RRuntime.DOUBLE_NA); - } else { - stream.writeDouble(val.getRealPart()); - stream.writeDouble(val.getImaginaryPart()); + RAbstractComplexVector vector = (RAbstractComplexVector) obj; + VectorAccess access = vector.slowPathAccess(); + try (SequentialIterator iter = access.access(vector)) { + stream.writeInt(access.getLength(iter)); + while (access.next(iter)) { + if (access.isNA(iter)) { + stream.writeDouble(RRuntime.DOUBLE_NA); + stream.writeDouble(RRuntime.DOUBLE_NA); + } else { + stream.writeDouble(access.getComplexR(iter)); + stream.writeDouble(access.getComplexI(iter)); + } } } break; @@ -1619,25 +1592,26 @@ public class RSerialize { case EXPRSXP: case VECSXP: { - RAbstractVector list; - if (type == SEXPTYPE.EXPRSXP) { - list = (RExpression) obj; - } else { - list = (RList) obj; - } - stream.writeInt(list.getLength()); - for (int i = 0; i < list.getLength(); i++) { - Object listObj = list.getDataAtAsObject(i); - writeItem(listObj); + RAbstractListBaseVector vector = (RAbstractListBaseVector) obj; + VectorAccess access = vector.slowPathAccess(); + try (SequentialIterator iter = access.access(vector)) { + stream.writeInt(access.getLength(iter)); + while (access.next(iter)) { + writeItem(access.getListElement(iter)); + } } break; } case RAWSXP: { - RRawVector raw = (RRawVector) obj; - byte[] data = raw.getReadonlyData(); - stream.writeInt(data.length); - stream.writeRaw(data); + RAbstractRawVector vector = (RAbstractRawVector) obj; + VectorAccess access = vector.slowPathAccess(); + try (SequentialIterator iter = access.access(vector)) { + stream.writeInt(access.getLength(iter)); + while (access.next(iter)) { + stream.writeRaw(access.getRaw(iter)); + } + } break; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java index 58096f6025f86d97235ed5018532a3b3f1ada2e3..ccd1f53dc14cbaf1b67fa087ba369dc6db7ecd82 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java @@ -96,6 +96,20 @@ public enum RType { } } + public boolean isAtomic() { + switch (this) { + case Logical: + case Double: + case Integer: + case Complex: + case Character: + case Raw: + return true; + default: + return false; + } + } + public boolean isVector() { switch (this) { case Logical: diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/NativeConnections.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/NativeConnections.java index 4f3a36f520cf162046f5b318e7107ccd075b4187..7d18153e4a3334d1cabe43c5d4001d8b2fbb265a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/NativeConnections.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/conn/NativeConnections.java @@ -302,7 +302,7 @@ public class NativeConnections { // converted to a pointer using RAW macro. This turns the raw vector into a native memory // backed vector and any consecutive (write) operations in the native code are actually not // done on the original vector that backs the byte buffer, so we need to copy back the date - // to the byte buffer. It would be more efficitent to use direct byte buffer, but then we'd + // to the byte buffer. It would be more efficient to use direct byte buffer, but then we'd // need to make the native call interface (CallRFFI.InvokeCallRootNode) more flexible so // that it can accept other argument types than SEXPs. diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java index efe8ee17d0ceaf1a7ce53e88b98587c6a012117b..ab9c0f0439bf4a9b41e4a692b41e6a4f572949cd 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/NativeDataAccess.java @@ -314,21 +314,35 @@ public final class NativeDataAccess { UnsafeAdapter.UNSAFE.getDouble(address + (index * 2 + 1) * Unsafe.ARRAY_DOUBLE_INDEX_SCALE)); } - public static void setNativeMirrorData(Object nativeMirror, int index, double value) { + public static double getComplexNativeMirrorDataR(Object nativeMirror, int index) { + long address = ((NativeMirror) nativeMirror).dataAddress; + assert address != 0; + assert index < ((NativeMirror) nativeMirror).length; + return UnsafeAdapter.UNSAFE.getDouble(address + index * 2 * Unsafe.ARRAY_DOUBLE_INDEX_SCALE); + } + + public static double getComplexNativeMirrorDataI(Object nativeMirror, int index) { + long address = ((NativeMirror) nativeMirror).dataAddress; + assert address != 0; + assert index < ((NativeMirror) nativeMirror).length; + return UnsafeAdapter.UNSAFE.getDouble(address + (index * 2 + 1) * Unsafe.ARRAY_DOUBLE_INDEX_SCALE); + } + + public static void setNativeMirrorDoubleData(Object nativeMirror, int index, double value) { long address = ((NativeMirror) nativeMirror).dataAddress; assert address != 0; assert index < ((NativeMirror) nativeMirror).length; UnsafeAdapter.UNSAFE.putDouble(address + index * Unsafe.ARRAY_DOUBLE_INDEX_SCALE, value); } - public static void setNativeMirrorData(Object nativeMirror, int index, byte value) { + public static void setNativeMirrorRawData(Object nativeMirror, int index, byte value) { long address = ((NativeMirror) nativeMirror).dataAddress; assert address != 0; assert index < ((NativeMirror) nativeMirror).length; UnsafeAdapter.UNSAFE.putByte(address + index * Unsafe.ARRAY_BYTE_INDEX_SCALE, value); } - public static void setNativeMirrorData(Object nativeMirror, int index, int value) { + public static void setNativeMirrorIntData(Object nativeMirror, int index, int value) { long address = ((NativeMirror) nativeMirror).dataAddress; assert address != 0; assert index < ((NativeMirror) nativeMirror).length; @@ -390,10 +404,14 @@ public final class NativeDataAccess { if (noIntNative.isValid() || data != null) { return data.length; } else { - return (int) ((NativeMirror) vector.getNativeMirror()).length; + return getDataLengthFromMirror(vector.getNativeMirror()); } } + static int getDataLengthFromMirror(Object mirror) { + return (int) ((NativeMirror) mirror).length; + } + static void setData(RIntVector vector, int[] data, int index, int value) { if (noIntNative.isValid() || data != null) { data[index] = value; @@ -478,7 +496,7 @@ public final class NativeDataAccess { if (noDoubleNative.isValid() || data != null) { data[index] = value; } else { - setNativeMirrorData(vector.getNativeMirror(), index, value); + setNativeMirrorDoubleData(vector.getNativeMirror(), index, value); } } @@ -490,6 +508,22 @@ public final class NativeDataAccess { } } + static double getDataR(RComplexVector vector, double[] data, int index) { + if (noComplexNative.isValid() || data != null) { + return data[index * 2]; + } else { + return getComplexNativeMirrorDataR(vector.getNativeMirror(), index); + } + } + + static double getDataI(RComplexVector vector, double[] data, int index) { + if (noComplexNative.isValid() || data != null) { + return data[index * 2 + 1]; + } else { + return getComplexNativeMirrorDataI(vector.getNativeMirror(), index); + } + } + static int getDataLength(RComplexVector vector, double[] data) { if (noComplexNative.isValid() || data != null) { return data.length >> 1; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java index a44c45ec7e53a2b1c5573d9b8e95511b6b98a377..ef5fb88f7cb06c6a13dc38ee7dccb3fecb069b6f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RAttributesLayout.java @@ -23,10 +23,8 @@ package com.oracle.truffle.r.runtime.data; import java.util.Collections; -import java.util.HashMap; import java.util.Iterator; import java.util.List; -import java.util.Map; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.CompilerDirectives.ValueType; @@ -59,72 +57,16 @@ public final class RAttributesLayout { private static final AttrsLayout NAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY); private static final AttrsLayout DIM_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIM_ATTR_KEY); private static final AttrsLayout DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIMNAMES_ATTR_KEY); + private static final AttrsLayout NAMES_AND_DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY, RRuntime.DIMNAMES_ATTR_KEY); private static final AttrsLayout ROWNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.ROWNAMES_ATTR_KEY); private static final AttrsLayout NAMES_AND_DIM_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY, RRuntime.DIM_ATTR_KEY); private static final AttrsLayout DIM_AND_DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.DIM_ATTR_KEY, RRuntime.DIMNAMES_ATTR_KEY); + private static final AttrsLayout NAMES_AND_DIM_AND_DIMNAMES_ATTRS_LAYOUT = new AttrsLayout(RRuntime.NAMES_ATTR_KEY, RRuntime.DIM_ATTR_KEY, RRuntime.DIMNAMES_ATTR_KEY); private static final AttrsLayout CLASS_AND_CONNID_ATTRS_LAYOUT = new AttrsLayout(RRuntime.CLASS_ATTR_KEY, RRuntime.CONN_ID_ATTR_KEY); public static final AttrsLayout[] LAYOUTS = {EMPTY_ATTRS_LAYOUT, CLASS_ATTRS_LAYOUT, NAMES_ATTRS_LAYOUT, DIM_ATTRS_LAYOUT, DIMNAMES_ATTRS_LAYOUT, ROWNAMES_ATTRS_LAYOUT, NAMES_AND_DIM_ATTRS_LAYOUT, DIM_AND_DIMNAMES_ATTRS_LAYOUT}; - private static final Map<String, ConstantShapesAndProperties> constantShapesAndLocationsForAttribute = new HashMap<>(); - - static { - constantShapesAndLocationsForAttribute.put(RRuntime.CLASS_ATTR_KEY, new ConstantShapesAndProperties( - new Shape[]{ - CLASS_ATTRS_LAYOUT.shape, - CLASS_AND_CONNID_ATTRS_LAYOUT.shape - }, - new Property[]{ - CLASS_ATTRS_LAYOUT.properties[0], - CLASS_AND_CONNID_ATTRS_LAYOUT.properties[0] - })); - constantShapesAndLocationsForAttribute.put(RRuntime.NAMES_ATTR_KEY, new ConstantShapesAndProperties( - new Shape[]{ - NAMES_ATTRS_LAYOUT.shape, - NAMES_AND_DIM_ATTRS_LAYOUT.shape - }, - new Property[]{ - NAMES_ATTRS_LAYOUT.properties[0], - NAMES_AND_DIM_ATTRS_LAYOUT.properties[0] - })); - constantShapesAndLocationsForAttribute.put(RRuntime.DIM_ATTR_KEY, new ConstantShapesAndProperties( - new Shape[]{ - DIM_ATTRS_LAYOUT.shape, - NAMES_AND_DIM_ATTRS_LAYOUT.shape, - DIM_AND_DIMNAMES_ATTRS_LAYOUT.shape - }, - new Property[]{ - DIM_ATTRS_LAYOUT.properties[0], - NAMES_AND_DIM_ATTRS_LAYOUT.properties[1], - DIM_AND_DIMNAMES_ATTRS_LAYOUT.properties[0] - })); - constantShapesAndLocationsForAttribute.put(RRuntime.DIMNAMES_ATTR_KEY, new ConstantShapesAndProperties( - new Shape[]{ - DIMNAMES_ATTRS_LAYOUT.shape, - DIM_AND_DIMNAMES_ATTRS_LAYOUT.shape - }, - new Property[]{ - DIMNAMES_ATTRS_LAYOUT.properties[0], - DIM_AND_DIMNAMES_ATTRS_LAYOUT.properties[1] - })); - constantShapesAndLocationsForAttribute.put(RRuntime.CONN_ID_ATTR_KEY, new ConstantShapesAndProperties( - new Shape[]{ - CLASS_AND_CONNID_ATTRS_LAYOUT.shape - }, - new Property[]{ - CLASS_AND_CONNID_ATTRS_LAYOUT.properties[0] - })); - constantShapesAndLocationsForAttribute.put(RRuntime.ROWNAMES_ATTR_KEY, new ConstantShapesAndProperties( - new Shape[]{ - ROWNAMES_ATTRS_LAYOUT.shape - }, - new Property[]{ - ROWNAMES_ATTRS_LAYOUT.properties[0] - })); - - } - private RAttributesLayout() { } @@ -155,6 +97,10 @@ public final class RAttributesLayout { return DIMNAMES_ATTRS_LAYOUT.factory.newInstance(dimNames); } + public static DynamicObject createNamesAndDimNames(Object names, Object dimNames) { + return NAMES_AND_DIMNAMES_ATTRS_LAYOUT.factory.newInstance(names, dimNames); + } + public static DynamicObject createRowNames(Object rowNames) { return ROWNAMES_ATTRS_LAYOUT.factory.newInstance(rowNames); } @@ -167,12 +113,12 @@ public final class RAttributesLayout { return DIM_AND_DIMNAMES_ATTRS_LAYOUT.factory.newInstance(dim, dimNames); } - public static DynamicObject createClassWithConnId(Object cls, Object connId) { - return CLASS_AND_CONNID_ATTRS_LAYOUT.factory.newInstance(cls, connId); + public static DynamicObject createNamesAndDimAndDimNames(Object names, Object dim, Object dimNames) { + return NAMES_AND_DIM_AND_DIMNAMES_ATTRS_LAYOUT.factory.newInstance(names, dim, dimNames); } - public static ConstantShapesAndProperties getConstantShapesAndProperties(String attrName) { - return constantShapesAndLocationsForAttribute.getOrDefault(attrName, ConstantShapesAndProperties.EMPTY); + public static DynamicObject createClassWithConnId(Object cls, Object connId) { + return CLASS_AND_CONNID_ATTRS_LAYOUT.factory.newInstance(cls, connId); } public static boolean isRAttributes(Object attrs) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java index af6a3028bc427305beaf140ce954cc6adc365b8d..367c91a77145feb4278e3fb36013a0832efa40aa 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplex.java @@ -30,7 +30,11 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromComplexAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromComplexAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; @ValueType public final class RComplex extends RScalarVector implements RAbstractComplexVector { @@ -143,4 +147,59 @@ public final class RComplex extends RScalarVector implements RAbstractComplexVec return Math.sqrt(re * re + im * im); } } + + private static final class FastPathAccess extends FastPathFromComplexAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected RComplex getComplex(Object store, int index) { + assert index == 0; + return (RComplex) store; + } + + @Override + protected double getComplexR(Object store, int index) { + assert index == 0; + return ((RComplex) store).realPart; + } + + @Override + protected double getComplexI(Object store, int index) { + assert index == 0; + return ((RComplex) store).imaginaryPart; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromComplexAccess SLOW_PATH_ACCESS = new SlowPathFromComplexAccess() { + @Override + protected RComplex getComplex(Object store, int index) { + assert index == 0; + return (RComplex) store; + } + + @Override + protected double getComplexR(Object store, int index) { + assert index == 0; + return ((RComplex) store).realPart; + } + + @Override + protected double getComplexI(Object store, int index) { + assert index == 0; + return ((RComplex) store).imaginaryPart; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java index a3cedbc0057006849cc31cfcfe2c7b37561b7d37..b42c2d6f77235b2467e3710f84f488c19e996cd0 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RComplexVector.java @@ -30,7 +30,11 @@ import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.closures.RClosures; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromComplexAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromComplexAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.ops.na.NACheck; public final class RComplexVector extends RVector<double[]> implements RAbstractComplexVector { @@ -41,7 +45,7 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract super(complete); assert data.length % 2 == 0; this.data = data; - assert verify(); + assert RAbstractVector.verify(this); } RComplexVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { @@ -104,10 +108,8 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract NativeDataAccess.setData(this, (double[]) store, index, value.getRealPart(), value.getImaginaryPart()); } - @Override - public RComplex getDataAt(Object store, int index) { - assert data == store; - return NativeDataAccess.getData(this, (double[]) store, index); + public void setDataAt(int index, RComplex value) { + NativeDataAccess.setData(this, data, index, value.getRealPart(), value.getImaginaryPart()); } @Override @@ -115,23 +117,6 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract return NativeDataAccess.getData(this, data, index); } - @Override - public String toString() { - return toString(i -> getDataAt(i).toString()); - } - - @Override - public boolean verify() { - if (isComplete()) { - for (int i = 0; i < getLength(); i++) { - if (getDataAt(i).isNA()) { - return false; - } - } - } - return true; - } - @Override public double[] getDataCopy() { if (data != null) { @@ -219,4 +204,73 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract complete = false; } } + + private static final class FastPathAccess extends FastPathFromComplexAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected RComplex getComplex(Object store, int index) { + return RComplex.valueOf(getComplexR(store, index), getComplexI(store, index)); + } + + @Override + protected double getComplexR(Object store, int index) { + return hasStore ? ((double[]) store)[index * 2] : NativeDataAccess.getDoubleNativeMirrorData(store, index * 2); + } + + @Override + protected double getComplexI(Object store, int index) { + return hasStore ? ((double[]) store)[index * 2 + 1] : NativeDataAccess.getDoubleNativeMirrorData(store, index * 2 + 1); + } + + @Override + protected void setComplex(Object store, int index, double real, double imaginary) { + if (hasStore) { + ((double[]) store)[index * 2] = real; + ((double[]) store)[index * 2 + 1] = imaginary; + } else { + NativeDataAccess.setNativeMirrorDoubleData(store, index * 2, real); + NativeDataAccess.setNativeMirrorDoubleData(store, index * 2 + 1, imaginary); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromComplexAccess SLOW_PATH_ACCESS = new SlowPathFromComplexAccess() { + @Override + protected RComplex getComplex(Object store, int index) { + RComplexVector vector = (RComplexVector) store; + return NativeDataAccess.getData(vector, vector.data, index); + } + + @Override + protected double getComplexR(Object store, int index) { + RComplexVector vector = (RComplexVector) store; + return NativeDataAccess.getDataR(vector, vector.data, index); + } + + @Override + protected double getComplexI(Object store, int index) { + RComplexVector vector = (RComplexVector) store; + return NativeDataAccess.getDataI(vector, vector.data, index); + } + + @Override + protected void setComplex(Object store, int index, double real, double imaginary) { + RComplexVector vector = (RComplexVector) store; + NativeDataAccess.setData(vector, vector.data, index, real, imaginary); + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java index be21c056a32b4f8646992314359d6a836e43bcc4..2587193a855ef1fc6a9fd79822a15f1459f97366 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDataFactory.java @@ -28,6 +28,7 @@ import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.atomic.AtomicInteger; import com.oracle.truffle.api.Assumption; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.RootCallTarget; @@ -35,10 +36,14 @@ import com.oracle.truffle.api.Truffle; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.instrumentation.AllocationReporter; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.nodes.NodeCost; +import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.builtins.RBuiltinDescriptor; import com.oracle.truffle.r.runtime.context.RContext; @@ -49,6 +54,729 @@ import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; public final class RDataFactory { + private abstract static class StaticVectorFactory extends BaseVectorFactory { + + @Override + public void reinitializeAttributes(RVector<?> vector, int[] dims, RStringVector names, RList dimNames) { + vector.initAttributes(dims != null || names != null || dimNames != null ? RVector.createAttributes(dims, names, dimNames) : null); + } + + @Override + protected <T extends RVector<?>> T initializeAttributes(T result, int[] dims, RStringVector names, RList dimNames) { + if (dims != null || names != null || dimNames != null) { + result.initDimsNamesDimNames(dims, names, dimNames); + } + return result; + } + + @Override + protected <T extends RVector<?>> T initializeAttributes(T result, int[] dims) { + if (dims != null) { + result.initDimsNamesDimNames(dims, null, null); + } + return result; + } + + @Override + protected <T extends RVector<?>> T initializeAttributes(T result, RStringVector names) { + if (names != null) { + result.initDimsNamesDimNames(null, names, null); + } + return result; + } + } + + private static final class DefaultStaticVectorFactory extends StaticVectorFactory { + + } + + private static final class PermanentStaticVectorFactory extends StaticVectorFactory { + + @Override + protected <T> T traceDataCreated(T data) { + if (data instanceof RShareable) { + ((RShareable) data).makeSharedPermanent(); + } else { + assert data instanceof Integer || data instanceof Double || data instanceof Byte || data instanceof String || data instanceof RRaw || + data instanceof RComplex : "cannot make permanent instance of non-shareable object"; + } + return super.traceDataCreated(data); + } + } + + private static final StaticVectorFactory INSTANCE = new DefaultStaticVectorFactory(); + private static final StaticVectorFactory PERMANENT = new PermanentStaticVectorFactory(); + + /** + * This factory is only intended for use on slow paths, all places where a node context is + * available should use a dynamic {@link VectorFactory} instance. + */ + public static BaseVectorFactory getInstance() { + CompilerAsserts.neverPartOfCompilation("RDataFactory.getInstance() can only be used in slow paths"); + return INSTANCE; + } + + /** + * This factory is intended for use in initializers that want to create "permanent" objects, + * i.e., objects that have their reference count set to "permanently shared". + */ + public static BaseVectorFactory getPermanent() { + CompilerAsserts.neverPartOfCompilation("RDataFactory.getPermanent() can only be used in slow paths"); + return PERMANENT; + } + + public static final class VectorFactory extends BaseVectorFactory { + + private VectorFactory() { + // private constructor + } + + private final ConditionProfile hasAttributes = ConditionProfile.createBinaryProfile(); + + @Override + public void reinitializeAttributes(RVector<?> vector, int[] dims, RStringVector names, RList dimNames) { + vector.initAttributes(hasAttributes.profile(dims != null || names != null || dimNames != null) ? RVector.createAttributes(dims, names, dimNames) : null); + } + + @Override + protected <T extends RVector<?>> T initializeAttributes(T result, int[] dims, RStringVector names, RList dimNames) { + if (hasAttributes.profile(dims != null || names != null || dimNames != null)) { + result.initDimsNamesDimNames(dims, names, dimNames); + } + return result; + } + + @Override + protected <T extends RVector<?>> T initializeAttributes(T result, int[] dims) { + if (hasAttributes.profile(dims != null)) { + result.initDimsNamesDimNames(dims, null, null); + } + return result; + } + + @Override + protected <T extends RVector<?>> T initializeAttributes(T result, RStringVector names) { + if (hasAttributes.profile(names != null)) { + result.initDimsNamesDimNames(null, names, null); + } + return result; + } + + public static VectorFactory create() { + return new VectorFactory(); + } + } + + @SuppressWarnings("static-method") + public abstract static class BaseVectorFactory extends Node { + + @Override + public final NodeCost getCost() { + return NodeCost.NONE; + } + + public abstract void reinitializeAttributes(RVector<?> vector, int[] dims, RStringVector names, RList dimNames); + + protected abstract <T extends RVector<?>> T initializeAttributes(T result, int[] dims, RStringVector names, RList dimNames); + + protected abstract <T extends RVector<?>> T initializeAttributes(T result, int[] dims); + + protected abstract <T extends RVector<?>> T initializeAttributes(T result, RStringVector names); + + protected <T> T traceDataCreated(T data) { + if (stateAssumption.isEnabled()) { + reportDataCreated(data); + } + return data; + } + + public final RIntVector createIntVector(int[] data, boolean complete) { + return traceDataCreated(new RIntVector(data, complete)); + } + + public final RIntVector createIntVector(int[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(initializeAttributes(new RIntVector(data, complete), dims, names, dimNames)); + } + + public final RIntVector createIntVector(int[] data, boolean complete, int[] dims) { + return traceDataCreated(initializeAttributes(new RIntVector(data, complete), dims)); + } + + public final RIntVector createIntVector(int[] data, boolean complete, RStringVector names) { + return traceDataCreated(initializeAttributes(new RIntVector(data, complete), names)); + } + + public final RDoubleVector createDoubleVector(double[] data, boolean complete) { + return traceDataCreated(new RDoubleVector(data, complete)); + } + + public final RDoubleVector createDoubleVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(initializeAttributes(new RDoubleVector(data, complete), dims, names, dimNames)); + } + + public final RDoubleVector createDoubleVector(double[] data, boolean complete, int[] dims) { + return traceDataCreated(initializeAttributes(new RDoubleVector(data, complete), dims)); + } + + public final RDoubleVector createDoubleVector(double[] data, boolean complete, RStringVector names) { + return traceDataCreated(initializeAttributes(new RDoubleVector(data, complete), names)); + } + + public final RLogicalVector createLogicalVector(byte[] data, boolean complete) { + return traceDataCreated(new RLogicalVector(data, complete)); + } + + public final RLogicalVector createLogicalVector(byte[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(initializeAttributes(new RLogicalVector(data, complete), dims, names, dimNames)); + } + + public final RLogicalVector createLogicalVector(byte[] data, boolean complete, int[] dims) { + return traceDataCreated(initializeAttributes(new RLogicalVector(data, complete), dims)); + } + + public final RLogicalVector createLogicalVector(byte[] data, boolean complete, RStringVector names) { + return traceDataCreated(initializeAttributes(new RLogicalVector(data, complete), names)); + } + + public final RStringVector createStringVector(String[] data, boolean complete) { + return traceDataCreated(new RStringVector(data, complete)); + } + + public final RStringVector createStringVector(String[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(initializeAttributes(new RStringVector(data, complete), dims, names, dimNames)); + } + + public final RStringVector createStringVector(String[] data, boolean complete, int[] dims) { + return traceDataCreated(initializeAttributes(new RStringVector(data, complete), dims)); + } + + public final RStringVector createStringVector(String[] data, boolean complete, RStringVector names) { + return traceDataCreated(initializeAttributes(new RStringVector(data, complete), names)); + } + + public final RComplexVector createComplexVector(double[] data, boolean complete) { + return traceDataCreated(new RComplexVector(data, complete)); + } + + public final RComplexVector createComplexVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(initializeAttributes(new RComplexVector(data, complete), dims, names, dimNames)); + } + + public final RComplexVector createComplexVector(double[] data, boolean complete, int[] dims) { + return traceDataCreated(initializeAttributes(new RComplexVector(data, complete), dims)); + } + + public final RComplexVector createComplexVector(double[] data, boolean complete, RStringVector names) { + return traceDataCreated(initializeAttributes(new RComplexVector(data, complete), names)); + } + + public final RRawVector createRawVector(byte[] data) { + return traceDataCreated(new RRawVector(data)); + } + + public final RRawVector createRawVector(byte[] data, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(initializeAttributes(new RRawVector(data), dims, names, dimNames)); + } + + public final RRawVector createRawVector(byte[] data, int[] dims) { + return traceDataCreated(initializeAttributes(new RRawVector(data), dims)); + } + + public final RRawVector createRawVector(byte[] data, RStringVector names) { + return traceDataCreated(initializeAttributes(new RRawVector(data), names)); + } + + public final RList createList(Object[] data) { + return traceDataCreated(new RList(data)); + } + + public final RList createList(Object[] data, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(initializeAttributes(new RList(data), dims, names, dimNames)); + } + + public final RList createList(Object[] data, int[] dims) { + return traceDataCreated(initializeAttributes(new RList(data), dims)); + } + + public final RList createList(Object[] data, RStringVector names) { + return traceDataCreated(initializeAttributes(new RList(data), names)); + } + + public RExpression createExpression(int size) { + return createExpression(createRNullArray(size)); + } + + public RExpression createExpression(int size, RStringVector names) { + if (names == null) { + return createExpression(size); + } + assert size == names.getLength(); + return createExpression(createRNullArray(size), names); + } + + public RExpression createExpression(Object[] data, int[] newDimensions) { + return traceDataCreated(new RExpression(data, newDimensions, null, null)); + } + + public RExpression createExpression(Object[] data, RStringVector names) { + return traceDataCreated(new RExpression(data, null, names, null)); + } + + public RExpression createExpression(Object[] data, int[] newDimensions, RStringVector names, RList dimNames) { + return traceDataCreated(new RExpression(data, newDimensions, names, dimNames)); + } + + public RExpression createExpression(Object[] data) { + return traceDataCreated(new RExpression(data, null, null, null)); + } + + public final RVector<?> createEmptyVector(RType type) { + switch (type) { + case Double: + return createEmptyDoubleVector(); + case Integer: + return createEmptyIntVector(); + case Complex: + return createEmptyComplexVector(); + case Logical: + return createEmptyLogicalVector(); + case Character: + return createEmptyStringVector(); + case Raw: + return createEmptyRawVector(); + case List: + return createList(new Object[0]); + default: + throw RInternalError.shouldNotReachHere(); + } + } + + public final RVector<?> createUninitializedVector(RType type, int length, int[] dims, RStringVector names, RList dimNames) { + switch (type) { + case Logical: + return createLogicalVector(new byte[length], false, dims, names, dimNames); + case Integer: + return createIntVector(new int[length], false, dims, names, dimNames); + case Double: + return createDoubleVector(new double[length], false, dims, names, dimNames); + case Complex: + return createComplexVector(new double[length * 2], false, dims, names, dimNames); + case Character: + return createStringVector(new String[length], false, dims, names, dimNames); + case Expression: { + Object[] data = new Object[length]; + Arrays.fill(data, RNull.instance); + return createExpression(data, dims, names, dimNames); + } + case List: { + Object[] data = new Object[length]; + Arrays.fill(data, RNull.instance); + return createList(data, dims, names, dimNames); + } + case Raw: + return createRawVector(new byte[length], dims, names, dimNames); + default: + throw RInternalError.shouldNotReachHere(); + } + + } + + public final RVector<?> createVector(RType type, int length, boolean fillNA) { + switch (type) { + case Logical: { + byte[] data = new byte[length]; + if (fillNA) { + Arrays.fill(data, RRuntime.LOGICAL_NA); + } + return createLogicalVector(data, !fillNA); + } + case Integer: { + int[] data = new int[length]; + if (fillNA) { + Arrays.fill(data, RRuntime.INT_NA); + } + return createIntVector(data, !fillNA); + } + case Double: { + double[] data = new double[length]; + if (fillNA) { + Arrays.fill(data, RRuntime.LOGICAL_NA); + } + return createDoubleVector(data, !fillNA); + } + case Complex: { + double[] data = new double[length * 2]; + if (fillNA) { + Arrays.fill(data, RRuntime.LOGICAL_NA); + for (int i = 0; i < data.length; i += 2) { + data[i] = RRuntime.COMPLEX_NA_REAL_PART; + data[i + 1] = RRuntime.COMPLEX_NA_IMAGINARY_PART; + } + } + return createComplexVector(data, !fillNA); + } + case Character: { + String[] data = new String[length]; + Arrays.fill(data, fillNA ? RRuntime.STRING_NA : ""); + return createStringVector(data, !fillNA); + } + case Expression: { + Object[] data = new Object[length]; + Arrays.fill(data, RNull.instance); + return createExpression(data); + } + case List: { + Object[] data = new Object[length]; + Arrays.fill(data, RNull.instance); + return createList(data); + } + case Raw: + return createRawVector(new byte[length]); + default: + throw RInternalError.shouldNotReachHere(); + } + } + + /* + * the following functions are not cleaned up yet: + */ + + public final RIntVector createIntVectorFromNative(long address, int length) { + return traceDataCreated(RIntVector.fromNative(address, length)); + } + + public final RIntVector createIntVector(int length) { + return createIntVector(new int[length], true); + } + + public final RDoubleVector createDoubleVectorFromNative(long address, int length) { + return traceDataCreated(RDoubleVector.fromNative(address, length)); + } + + public final RDoubleVector createDoubleVector(int length) { + return createDoubleVector(new double[length], true); + } + + public final RRawVector createRawVector(int length) { + return createRawVector(new byte[length]); + } + + public final RComplexVector createComplexVectorFromNative(long address, int length) { + return traceDataCreated(RComplexVector.fromNative(address, length)); + } + + public final RComplexVector createComplexVector(int length) { + return createComplexVector(new double[length << 1], true); + } + + public final RStringVector createStringVector(String value) { + return createStringVector(new String[]{value}, !RRuntime.isNA(value)); + } + + public final RStringVector createStringVector(int length) { + return createStringVector(createAndfillStringVector(length, ""), true); + } + + private static String[] createAndfillStringVector(int length, String string) { + String[] strings = new String[length]; + Arrays.fill(strings, string); + return strings; + } + + public final RLogicalVector createLogicalVectorFromNative(long address, int length) { + return traceDataCreated(RLogicalVector.fromNative(address, length)); + } + + public final RLogicalVector createLogicalVector(int length) { + return createLogicalVector(length, false); + } + + public final RLogicalVector createLogicalVector(int length, boolean fillNA) { + byte[] data = new byte[length]; + if (fillNA) { + Arrays.fill(data, RRuntime.LOGICAL_NA); + } + return createLogicalVector(data, !fillNA); + } + + public final RIntSequence createAscendingRange(int start, int end) { + assert start <= end; + return traceDataCreated(new RIntSequence(start, 1, end - start + 1)); + } + + public final RIntSequence createDescendingRange(int start, int end) { + assert start > end; + return traceDataCreated(new RIntSequence(start, -1, start - end + 1)); + } + + public final RIntSequence createIntSequence(int start, int stride, int length) { + return traceDataCreated(new RIntSequence(start, stride, length)); + } + + public final RDoubleSequence createAscendingRange(double start, double end) { + assert start <= end; + return traceDataCreated(new RDoubleSequence(start, 1, (int) ((end - start) + 1))); + } + + public final RDoubleSequence createDescendingRange(double start, double end) { + assert start > end; + return traceDataCreated(new RDoubleSequence(start, -1, (int) ((start - end) + 1))); + } + + public final RDoubleSequence createDoubleSequence(double start, double stride, int length) { + return traceDataCreated(new RDoubleSequence(start, stride, length)); + } + + public final RIntVector createEmptyIntVector() { + return createIntVector(new int[0], true); + } + + public final RDoubleVector createEmptyDoubleVector() { + return createDoubleVector(new double[0], true); + } + + public final RStringVector createEmptyStringVector() { + return createStringVector(new String[0], true); + } + + public final RStringVector createNAStringVector() { + return createStringVector(new String[]{RRuntime.STRING_NA}, false); + } + + public final RStringSequence createStringSequence(String prefix, String suffix, int start, int stride, int length) { + return traceDataCreated(new RStringSequence(prefix, suffix, start, stride, length)); + } + + public final RComplexVector createEmptyComplexVector() { + return createComplexVector(new double[0], true); + } + + public final RLogicalVector createEmptyLogicalVector() { + return createLogicalVector(new byte[0], true); + } + + public final RRawVector createEmptyRawVector() { + return createRawVector(new byte[0]); + } + + public final RList createEmptyList() { + return createList(new Object[0]); + } + + public final RComplex createComplex(double realPart, double imaginaryPart) { + return traceDataCreated(RComplex.valueOf(realPart, imaginaryPart)); + } + + public final RRawVector createRawVectorFromNative(long address, int length) { + return traceDataCreated(RRawVector.fromNative(address, length)); + } + + public final RRaw createRaw(byte value) { + return traceDataCreated(new RRaw(value)); + } + + /* + * Shared scalar conversion functions: these need to be replaced with + * createXyzVectorFromScalar(...).makeSharedPermanent() if scalar types are removed. + */ + + public final Object createSharedStringVectorFromScalar(String value) { + return value; + } + + public final Object createSharedLogicalVectorFromScalar(boolean value) { + return RRuntime.asLogical(value); + } + + public final Object createSharedLogicalVectorFromScalar(byte value) { + return value; + } + + public final Object createSharedIntVectorFromScalar(int value) { + return value; + } + + public final Object createSharedDoubleVectorFromScalar(double value) { + return value; + } + + public final Object createSharedComplexVectorFromScalar(RComplex value) { + return value; + } + + public final Object createSharedRawVectorFromScalar(RRaw value) { + return value; + } + + public final RList createList(int n) { + return createList(createRNullArray(n)); + } + + public final RList createList(Object[] data, int[] newDimensions, RStringVector names) { + return traceDataCreated(new RList(data, newDimensions, names, null)); + } + + public final RSymbol createSymbol(String name) { + assert Utils.isInterned(name); + return traceDataCreated(new RSymbol(name)); + } + + /* + * A version of {@link createSymbol} method mostly used from native code and in + * serialization/deparsing. + */ + public final RSymbol createSymbolInterned(String name) { + return createSymbol(Utils.intern(name)); + } + + public final RLanguage createLanguage(Closure closure) { + return traceDataCreated(new RLanguage(closure)); + } + + public final RPromise createPromise(PromiseState state, Closure closure, MaterializedFrame env) { + assert closure != null; + assert closure.getExpr() != null; + return traceDataCreated(new RPromise(state, env, closure)); + } + + public final RPromise createEvaluatedPromise(PromiseState state, Closure closure, Object argumentValue) { + return traceDataCreated(new RPromise(state, closure, argumentValue)); + } + + public final RPromise createEvaluatedPromise(Closure closure, Object value) { + return traceDataCreated(new RPromise(PromiseState.Explicit, closure, value)); + } + + public RPromise createEagerPromise(PromiseState state, Closure exprClosure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback, + int wrapIndex, MaterializedFrame execFrame) { + if (FastROptions.noEagerEval()) { + throw RInternalError.shouldNotReachHere(); + } + return traceDataCreated(new RPromise.EagerPromise(state, exprClosure, eagerValue, notChangedNonLocally, targetFrame, feedback, wrapIndex, execFrame)); + } + + public RPromise createPromisedPromise(Closure exprClosure, Object eagerValue, Assumption notChangedNonLocally, RCaller targetFrame, EagerFeedback feedback, MaterializedFrame execFrame) { + if (FastROptions.noEagerEval()) { + throw RInternalError.shouldNotReachHere(); + } + return traceDataCreated(new RPromise.EagerPromise(PromiseState.Promised, exprClosure, eagerValue, notChangedNonLocally, targetFrame, feedback, -1, execFrame)); + } + + public final Object createLangPairList(int size) { + if (size == 0) { + return RNull.instance; + } else { + return traceDataCreated(RPairList.create(size, SEXPTYPE.LANGSXP)); + } + } + + public final Object createPairList(int size) { + if (size == 0) { + return RNull.instance; + } else { + return traceDataCreated(RPairList.create(size)); + } + } + + public final RPairList createPairList() { + return traceDataCreated(new RPairList()); + } + + public final RPairList createPairList(Object car) { + + return traceDataCreated(new RPairList(car, RNull.instance, RNull.instance, null)); + } + + public final RPairList createPairList(Object car, Object cdr) { + return traceDataCreated(new RPairList(car, cdr, RNull.instance, null)); + } + + public final RPairList createPairList(Object car, Object cdr, Object tag) { + return traceDataCreated(new RPairList(car, cdr, tag, null)); + } + + public final RPairList createPairList(Object car, Object cdr, Object tag, SEXPTYPE type) { + return traceDataCreated(new RPairList(car, cdr, tag, type)); + } + + public final RFunction createFunction(String name, String packageName, RootCallTarget target, RBuiltinDescriptor builtin, MaterializedFrame enclosingFrame) { + return traceDataCreated(new RFunction(name, packageName, target, builtin, enclosingFrame)); + } + + private static final AtomicInteger environmentCount = new AtomicInteger(); + + @TruffleBoundary + public final REnvironment createInternalEnv() { + return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNonFunctionFrame("<internal-env-" + environmentCount.incrementAndGet() + ">"), REnvironment.UNNAMED)); + } + + @TruffleBoundary + public final REnvironment.NewEnv createNewEnv(FrameDescriptor desc, String name) { + return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNewFrame(desc), name)); + } + + @TruffleBoundary + public final REnvironment.NewEnv createNewEnv(String name) { + return traceDataCreated(new REnvironment.NewEnv(RRuntime.createNonFunctionFrame("<new-env-" + environmentCount.incrementAndGet() + ">"), name)); + } + + @TruffleBoundary + public final REnvironment createNewEnv(String name, boolean hashed, int initialSize) { + REnvironment.NewEnv env = new REnvironment.NewEnv(RRuntime.createNonFunctionFrame("<new-env-" + environmentCount.incrementAndGet() + ">"), name); + env.setHashed(hashed); + env.setInitialSize(initialSize); + return traceDataCreated(env); + } + + public final RS4Object createS4Object() { + return traceDataCreated(new RS4Object()); + } + + public final RExternalPtr createExternalPtr(SymbolHandle value, Object externalObject, Object tag, Object prot) { + assert tag != null : "null tag, use RNull.instance instead"; + assert prot != null : "null prot, use RNull.instance instead"; + return traceDataCreated(new RExternalPtr(value, externalObject, tag, prot)); + } + + public final RExternalPtr createExternalPtr(SymbolHandle value, Object tag, Object prot) { + assert tag != null : "null tag, use RNull.instance instead"; + assert prot != null : "null prot, use RNull.instance instead"; + return traceDataCreated(new RExternalPtr(value, null, tag, prot)); + } + + public final RExternalPtr createExternalPtr(SymbolHandle value, Object tag) { + assert tag != null : "null tag, use RNull.instance instead"; + return traceDataCreated(new RExternalPtr(value, null, tag, RNull.instance)); + } + + public RStringVector createStringVectorFromScalar(String value) { + return traceDataCreated(RDataFactory.createStringVectorFromScalar(value)); + } + + public RLogicalVector createLogicalVectorFromScalar(boolean value) { + return traceDataCreated(RDataFactory.createLogicalVectorFromScalar(value)); + } + + public RLogicalVector createLogicalVectorFromScalar(byte value) { + return traceDataCreated(RDataFactory.createLogicalVectorFromScalar(value)); + } + + public RIntVector createIntVectorFromScalar(int value) { + return traceDataCreated(RDataFactory.createIntVectorFromScalar(value)); + } + + public RDoubleVector createDoubleVectorFromScalar(double value) { + return traceDataCreated(RDataFactory.createDoubleVectorFromScalar(value)); + } + + public RComplexVector createComplexVectorFromScalar(RComplex value) { + return traceDataCreated(RDataFactory.createComplexVectorFromScalar(value)); + } + + public RRawVector createRawVectorFromScalar(RRaw value) { + return traceDataCreated(RDataFactory.createRawVectorFromScalar(value)); + } + } public static final boolean INCOMPLETE_VECTOR = false; public static final boolean COMPLETE_VECTOR = true; @@ -456,15 +1184,15 @@ public final class RDataFactory { } public static RExpression createExpression(Object[] data, int[] newDimensions) { - return traceDataCreated(new RExpression(data, newDimensions, null)); + return traceDataCreated(new RExpression(data, newDimensions, null, null)); } public static RExpression createExpression(Object[] data, RStringVector names) { - return traceDataCreated(new RExpression(data, null, names)); + return traceDataCreated(new RExpression(data, null, names, null)); } public static RExpression createExpression(Object[] data) { - return traceDataCreated(new RExpression(data, null, null)); + return traceDataCreated(new RExpression(data, null, null, null)); } public static RSymbol createSymbol(String name) { diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java index 6a66889e9cdeacff4129c7ab932ead664ee736bb..c0eff99975609d55764d3c577845f1e058bd7c30 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDouble.java @@ -28,8 +28,12 @@ import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; @ValueType public final class RDouble extends RScalarVector implements RAbstractDoubleVector { @@ -99,4 +103,35 @@ public final class RDouble extends RScalarVector implements RAbstractDoubleVecto public boolean isNA() { return RRuntime.isNA(getValue()); } + + private static final class FastPathAccess extends FastPathFromDoubleAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected double getDouble(Object store, int index) { + assert index == 0; + return ((RDouble) store).value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromDoubleAccess SLOW_PATH_ACCESS = new SlowPathFromDoubleAccess() { + @Override + protected double getDouble(Object store, int index) { + assert index == 0; + return ((RDouble) store).value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java index a94cce37d00277922034d1d28749b204d1ebf17c..5d0ca6da84706471cdb8dfab9c8f4fb31f8dc2c8 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleSequence.java @@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; public final class RDoubleSequence extends RSequence implements RAbstractDoubleVector { @@ -134,4 +138,37 @@ public final class RDoubleSequence extends RSequence implements RAbstractDoubleV CompilerAsserts.neverPartOfCompilation(); return "[" + start + " - " + getEnd() + "]"; } + + private static final class FastPathAccess extends FastPathFromDoubleAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected double getDouble(Object store, int index) { + RDoubleSequence vector = (RDoubleSequence) store; + assert index >= 0 && index < vector.getLength(); + return vector.start + vector.stride * index; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromDoubleAccess SLOW_PATH_ACCESS = new SlowPathFromDoubleAccess() { + @Override + protected double getDouble(Object store, int index) { + RDoubleSequence vector = (RDoubleSequence) store; + assert index >= 0 && index < vector.getLength(); + return vector.start + vector.stride * index; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java index cc84373f42bcae0a9f153044ac545d4700966526..e37787fd868e78c8d4c0f6523e10dbc293eb290d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RDoubleVector.java @@ -29,8 +29,12 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.ops.na.NACheck; public final class RDoubleVector extends RVector<double[]> implements RAbstractDoubleVector { @@ -40,7 +44,7 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD RDoubleVector(double[] data, boolean complete) { super(complete); this.data = data; - assert verify(); + assert RAbstractVector.verify(this); } RDoubleVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { @@ -99,6 +103,10 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD NativeDataAccess.setData(this, (double[]) store, index, value); } + public void setDataAt(int index, double value) { + NativeDataAccess.setData(this, data, index, value); + } + @Override public double getDataAt(Object store, int index) { assert data == store; @@ -123,23 +131,6 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD return NativeDataAccess.getDataLength(this, data); } - @Override - public String toString() { - return toString(i -> Double.toString(getDataAt(i))); - } - - @Override - public boolean verify() { - if (isComplete()) { - for (int i = 0; i < getLength(); i++) { - if (RRuntime.isNA(getDataAt(i))) { - return false; - } - } - } - return true; - } - @Override public double getDataAt(int index) { return NativeDataAccess.getData(this, data, index); @@ -238,4 +229,49 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD complete = false; } } + + private static final class FastPathAccess extends FastPathFromDoubleAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected double getDouble(Object store, int index) { + return hasStore ? ((double[]) store)[index] : NativeDataAccess.getDoubleNativeMirrorData(store, index); + } + + @Override + protected void setDouble(Object store, int index, double value) { + if (hasStore) { + ((double[]) store)[index] = value; + } else { + NativeDataAccess.setNativeMirrorDoubleData(store, index, value); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromDoubleAccess SLOW_PATH_ACCESS = new SlowPathFromDoubleAccess() { + @Override + protected double getDouble(Object store, int index) { + RDoubleVector vector = (RDoubleVector) store; + return NativeDataAccess.getData(vector, vector.data, index); + } + + @Override + protected void setDouble(Object store, int index, double value) { + RDoubleVector vector = (RDoubleVector) store; + NativeDataAccess.setData(vector, vector.data, index, value); + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java index 2e0463d5598a60d179459766246a95f4569ab2c7..1c9e240c9a7f3e42462694c12f8991a7a89cbe9d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExpression.java @@ -26,12 +26,20 @@ import java.util.Arrays; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; public final class RExpression extends RListBase implements RAbstractVector { - RExpression(Object[] data, int[] dims, RStringVector names) { - super(data, dims, names, null); + RExpression(Object[] data) { + super(data); + } + + RExpression(Object[] data, int[] dims, RStringVector names, RList dimNames) { + super(data, dims, names, dimNames); } @Override @@ -47,7 +55,7 @@ public final class RExpression extends RListBase implements RAbstractVector { @Override @TruffleBoundary protected RExpression internalCopy() { - return new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null); + return new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null, null); } @Override @@ -55,7 +63,7 @@ public final class RExpression extends RListBase implements RAbstractVector { protected RExpression internalDeepCopy() { // TOOD: only used for nested list updates, but still could be made faster (through a // separate AST node?) - RExpression listCopy = new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null); + RExpression listCopy = new RExpression(Arrays.copyOf(data, data.length), getDimensions(), null, null); for (int i = 0; i < listCopy.getLength(); i++) { Object el = listCopy.getDataAt(i); if (el instanceof RVector) { @@ -80,4 +88,53 @@ public final class RExpression extends RListBase implements RAbstractVector { protected RExpression internalCopyResized(int size, boolean fillNA, int[] dimensions) { return RDataFactory.createExpression(copyResizedData(size, fillNA), dimensions); } + + private static final class FastPathAccess extends FastPathFromListAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + public RType getType() { + return RType.Expression; + } + + @Override + protected Object getListElement(Object store, int index) { + return ((Object[]) store)[index]; + } + + @Override + protected void setListElement(Object store, int index, Object value) { + ((Object[]) store)[index] = value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() { + @Override + public RType getType() { + return RType.Expression; + } + + @Override + protected Object getListElement(Object store, int index) { + return ((RExpression) store).data[index]; + } + + @Override + protected void setListElement(Object store, int index, Object value) { + ((RExpression) store).data[index] = value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java index 57aa7933b90f2b5c600d539a1aef31aa713390cd..fa03686af947f9cc3137ef97fbcb97ac4f14b686 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RExternalPtr.java @@ -28,7 +28,7 @@ import com.oracle.truffle.r.runtime.ffi.DLL.SymbolHandle; /** * The rarely seen {@code externalptr} type used in native code. */ -public class RExternalPtr extends RAttributeStorage implements RTypedValue { +public final class RExternalPtr extends RAttributeStorage implements RTypedValue { /** * In GNU R, typically the address of some C structure, so a {@code void*}. Represented here as * our abstraction of a "native symbol" (even though there may not actually be a symbol diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java index 3d0746749a6a04225b2d39b7fd2d57a6f48afb92..cbda3db37fcf51e570ed59b5d818f7f2a1f392d5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFactor.java @@ -36,10 +36,7 @@ public final class RFactor { * be replaced with FactorNodes.GetLevel in the future. */ public static RVector<?> getLevels(RAbstractIntVector factor) { - return getLevelsImpl(factor.getAttr(RRuntime.LEVELS_ATTR_KEY)); - } - - private static RVector<?> getLevelsImpl(Object attr) { + Object attr = factor.getAttr(RRuntime.LEVELS_ATTR_KEY); // convert scalar to RVector<?>if necessary return attr instanceof RVector ? (RVector<?>) attr : (RVector<?>) RRuntime.asAbstractVector(attr); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignBooleanWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignBooleanWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..b3c30b09276c0864281b5cbd856c0b8cb0c876ea --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignBooleanWrapper.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromLogicalAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromLogicalAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; + +public final class RForeignBooleanWrapper extends RForeignWrapper implements RAbstractLogicalVector { + + public RForeignBooleanWrapper(TruffleObject delegate) { + super(delegate); + } + + @Override + public RLogicalVector materialize() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + @TruffleBoundary + public Object getDataAtAsObject(int index) { + return getDataAt(index); + } + + @Override + @TruffleBoundary + public byte getDataAt(int index) { + try { + return RRuntime.asLogical((boolean) ForeignAccess.sendRead(READ, delegate, index)); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + private static final class FastPathAccess extends FastPathFromLogicalAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Child private Node getSize = Message.GET_SIZE.createNode(); + @Child private Node read = Message.READ.createNode(); + + @Override + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected byte getLogical(Object internalStore, int index) { + try { + return RRuntime.asLogical((boolean) ForeignAccess.sendRead(read, (TruffleObject) internalStore, index)); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromLogicalAccess SLOW_PATH_ACCESS = new SlowPathFromLogicalAccess() { + @Override + @TruffleBoundary + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignBooleanWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected byte getLogical(Object store, int index) { + RForeignBooleanWrapper vector = (RForeignBooleanWrapper) store; + try { + return RRuntime.asLogical((boolean) ForeignAccess.sendRead(READ, vector.delegate, index)); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignDoubleWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignDoubleWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..90dbbe7faf6395e88a163bef390b916e28a1bf28 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignDoubleWrapper.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; + +public final class RForeignDoubleWrapper extends RForeignWrapper implements RAbstractDoubleVector { + + public RForeignDoubleWrapper(TruffleObject delegate) { + super(delegate); + } + + @Override + public RDoubleVector materialize() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + @TruffleBoundary + public Object getDataAtAsObject(int index) { + return getDataAt(index); + } + + @Override + @TruffleBoundary + public double getDataAt(int index) { + try { + return ((Number) ForeignAccess.sendRead(READ, delegate, index)).doubleValue(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + private static final class FastPathAccess extends FastPathFromDoubleAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + private final ValueProfile resultProfile = ValueProfile.createClassProfile(); + @Child private Node getSize = Message.GET_SIZE.createNode(); + @Child private Node read = Message.READ.createNode(); + + @Override + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected double getDouble(Object internalStore, int index) { + try { + return ((Number) resultProfile.profile(ForeignAccess.sendRead(read, (TruffleObject) internalStore, index))).doubleValue(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromDoubleAccess SLOW_PATH_ACCESS = new SlowPathFromDoubleAccess() { + @Override + @TruffleBoundary + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignDoubleWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected double getDouble(Object store, int index) { + RForeignDoubleWrapper vector = (RForeignDoubleWrapper) store; + try { + return ((Number) ForeignAccess.sendRead(READ, vector.delegate, index)).doubleValue(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignIntWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignIntWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..68c4ca07ead520b8c62cc97ba41b58f6a5b94e98 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignIntWrapper.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; + +public final class RForeignIntWrapper extends RForeignWrapper implements RAbstractIntVector { + + public RForeignIntWrapper(TruffleObject delegate) { + super(delegate); + } + + @Override + public RIntVector materialize() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + @TruffleBoundary + public Object getDataAtAsObject(int index) { + return getDataAt(index); + } + + @Override + @TruffleBoundary + public int getDataAt(int index) { + try { + return ((Number) ForeignAccess.sendRead(READ, delegate, index)).intValue(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + private static final class FastPathAccess extends FastPathFromIntAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + private final ValueProfile resultProfile = ValueProfile.createClassProfile(); + @Child private Node getSize = Message.GET_SIZE.createNode(); + @Child private Node read = Message.READ.createNode(); + + @Override + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected int getInt(Object internalStore, int index) { + try { + return ((Number) resultProfile.profile(ForeignAccess.sendRead(read, (TruffleObject) internalStore, index))).intValue(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromIntAccess SLOW_PATH_ACCESS = new SlowPathFromIntAccess() { + @Override + @TruffleBoundary + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignIntWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected int getInt(Object store, int index) { + RForeignIntWrapper vector = (RForeignIntWrapper) store; + try { + return ((Number) ForeignAccess.sendRead(READ, vector.delegate, index)).intValue(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignListWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignListWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..20f59b813a625a99f5a3308fb9dd0a8feb549e2b --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignListWrapper.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.interop.Foreign2R; + +public final class RForeignListWrapper extends RForeignWrapper implements RAbstractListVector { + + public RForeignListWrapper(TruffleObject delegate) { + super(delegate); + } + + @Override + public RList materialize() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + @TruffleBoundary + public Object getDataAtAsObject(int index) { + return getDataAt(index); + } + + @Override + @TruffleBoundary + public Object getDataAt(int index) { + try { + return FOREIGN_TO_R.execute(ForeignAccess.sendRead(READ, delegate, index)); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + private static final class FastPathAccess extends FastPathFromListAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Child private Node getSize = Message.GET_SIZE.createNode(); + @Child private Node read = Message.READ.createNode(); + @Child private Foreign2R foreign2r = Foreign2R.create(); + + @Override + public RType getType() { + return RType.List; + } + + @Override + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected Object getListElement(Object internalStore, int index) { + try { + return foreign2r.execute(ForeignAccess.sendRead(read, (TruffleObject) internalStore, index)); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final Foreign2R FOREIGN_TO_R = Foreign2R.create(); + + private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() { + + @Override + public RType getType() { + return RType.List; + } + + @Override + @TruffleBoundary + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignListWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected Object getListElement(Object store, int index) { + RForeignListWrapper vector = (RForeignListWrapper) store; + try { + return FOREIGN_TO_R.execute(ForeignAccess.sendRead(READ, vector.delegate, index)); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignNamedListWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignNamedListWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..5c3be432639391b85ea7362c6c8bb0bc178392d2 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignNamedListWrapper.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.interop.Foreign2R; + +public final class RForeignNamedListWrapper extends RForeignWrapper implements RAbstractListVector { + + private final RStringVector names; + + public RForeignNamedListWrapper(TruffleObject delegate, RStringVector names) { + super(delegate); + this.names = names; + } + + @Override + public Object getInternalStore() { + return this; + } + + @Override + public int getLength() { + return names.getLength(); + } + + @Override + public RStringVector getNames() { + return names; + } + + @Override + public RList materialize() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + @TruffleBoundary + public Object getDataAtAsObject(int index) { + return getDataAt(index); + } + + @Override + @TruffleBoundary + public Object getDataAt(int index) { + try { + return FOREIGN_TO_R.execute(ForeignAccess.sendRead(READ, delegate, names.getDataAt(index))); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + private static final class FastPathAccess extends FastPathFromListAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Child private Node getSize = Message.GET_SIZE.createNode(); + @Child private Node read = Message.READ.createNode(); + @Child private Foreign2R foreign2r = Foreign2R.create(); + + @Override + public RType getType() { + return RType.List; + } + + @Override + protected int getLength(RAbstractContainer vector) { + return ((RForeignNamedListWrapper) vector).getLength(); + } + + @Override + protected Object getListElement(Object internalStore, int index) { + try { + RForeignNamedListWrapper wrapper = (RForeignNamedListWrapper) internalStore; + return foreign2r.execute(ForeignAccess.sendRead(read, wrapper.delegate, wrapper.names.getDataAt(index))); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final Foreign2R FOREIGN_TO_R = Foreign2R.create(); + + private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() { + @Override + public RType getType() { + return RType.List; + } + + @Override + @TruffleBoundary + protected int getLength(RAbstractContainer vector) { + return ((RForeignNamedListWrapper) vector).names.getLength(); + } + + @Override + protected Object getListElement(Object store, int index) { + RForeignNamedListWrapper vector = (RForeignNamedListWrapper) store; + try { + return FOREIGN_TO_R.execute(ForeignAccess.sendRead(READ, vector.delegate, vector.names.getDataAt(index))); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignStringWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignStringWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..148bb9cf13a968cb98a128ef7cf69d20a3d21c8f --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignStringWrapper.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnknownIdentifierException; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; + +public final class RForeignStringWrapper extends RForeignWrapper implements RAbstractStringVector { + + public RForeignStringWrapper(TruffleObject delegate) { + super(delegate); + } + + @Override + public RStringVector materialize() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + @TruffleBoundary + public Object getDataAtAsObject(int index) { + return getDataAt(index); + } + + @Override + @TruffleBoundary + public String getDataAt(int index) { + try { + return ForeignAccess.sendRead(READ, delegate, index).toString(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + private static final class FastPathAccess extends FastPathFromStringAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + private final ValueProfile resultProfile = ValueProfile.createClassProfile(); + @Child private Node getSize = Message.GET_SIZE.createNode(); + @Child private Node read = Message.READ.createNode(); + + @Override + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(getSize, ((RForeignWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + protected String getString(Object internalStore, int index) { + try { + return resultProfile.profile(ForeignAccess.sendRead(read, (TruffleObject) internalStore, index)).toString(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromStringAccess SLOW_PATH_ACCESS = new SlowPathFromStringAccess() { + @Override + @TruffleBoundary + protected int getLength(RAbstractContainer vector) { + try { + return (int) ForeignAccess.sendGetSize(GET_SIZE, ((RForeignStringWrapper) vector).delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + @TruffleBoundary + protected String getString(Object store, int index) { + RForeignStringWrapper vector = (RForeignStringWrapper) store; + try { + return ForeignAccess.sendRead(READ, vector.delegate, index).toString(); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignWrapper.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..36fece25f3205667f6fae6080373c2bb3e06e2ce --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RForeignWrapper.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public abstract class RForeignWrapper implements RAbstractVector { + + protected static final Node GET_SIZE = Message.GET_SIZE.createNode(); + protected static final Node READ = Message.READ.createNode(); + + protected final TruffleObject delegate; + + protected RForeignWrapper(TruffleObject delegate) { + this.delegate = delegate; + } + + @Override + @TruffleBoundary + public int getLength() { + try { + return (int) ForeignAccess.sendGetSize(GET_SIZE, delegate); + } catch (UnsupportedMessageException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + + @Override + public final RAbstractContainer resize(int size) { + return materialize().resize(size); + } + + @Override + public final boolean isComplete() { + return true; + } + + @Override + public final void setComplete(boolean complete) { + // sequences are always complete + } + + @Override + public final boolean hasDimensions() { + return false; + } + + @Override + public final int[] getDimensions() { + return null; + } + + @Override + public final void setDimensions(int[] newDimensions) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final RAbstractVector copy() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final RAbstractVector copyDropAttributes() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final RAbstractVector copyWithNewDimensions(int[] newDimensions) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public RStringVector getNames() { + return null; + } + + @Override + public final void setNames(RStringVector newNames) { + // should only be used on materialized sequence + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final RList getDimNames() { + return null; + } + + @Override + public final void setDimNames(RList newDimNames) { + // should only be used on materialized sequence + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final Object getRowNames() { + return RNull.instance; + } + + @Override + public final void setRowNames(RAbstractVector rowNames) { + // should only be used on materialized sequence + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final DynamicObject initAttributes() { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final void initAttributes(DynamicObject newAttributes) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final DynamicObject getAttributes() { + return null; + } + + @Override + public final boolean isMatrix() { + return false; + } + + @Override + public final boolean isArray() { + return false; + } + + @Override + public final boolean isObject() { + return false; + } + + @Override + public final RTypedValue getNonShared() { + return materialize().getNonShared(); + } + + @Override + public final int getTypedValueInfo() { + return 0; + } + + @Override + public final void setTypedValueInfo(int value) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final boolean isS4() { + return false; + } + + @Override + public Object getInternalStore() { + return delegate; + } + + @Override + public final RVector<?> copyResized(int size, boolean fillNA) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final RVector<?> copyResizedWithDimensions(int[] newDimensions, boolean fillNA) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + public final RVector<?> createEmptySameType(int newLength, boolean newIsComplete) { + throw RInternalError.shouldNotReachHere(); + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java index 6aa8daa0c098e2863619e687adda0594003a5387..7f7bd897580a991874dfb294c3693ce0e0abf08c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RFunction.java @@ -70,7 +70,7 @@ public final class RFunction extends RSharingAttributeStorage implements RTypedV public RType getRType() { // Note: GnuR distinguishes "builtins" and "specials" (BUILTINSXP vs SPECIALSXP). The later // has non-evaluated args. FastR and GnuR built-ins differ in whether they have evaluated - // args, so we cannot correcly choose RType.Special here. + // args, so we cannot correctly choose RType.Special here. return isBuiltin() ? RType.Builtin : RType.Closure; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java index c0e25112c797a7e35d47f0098c827da16367249d..5182f8cba14c7c50db1c932b1a62764ef4fb36cf 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntSequence.java @@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; public final class RIntSequence extends RSequence implements RAbstractIntVector { @@ -143,4 +147,37 @@ public final class RIntSequence extends RSequence implements RAbstractIntVector public RIntVector createEmptySameType(int newLength, boolean newIsComplete) { return RDataFactory.createIntVector(new int[newLength], newIsComplete); } + + private static final class FastPathAccess extends FastPathFromIntAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected int getInt(Object store, int index) { + RIntSequence vector = (RIntSequence) store; + assert index >= 0 && index < vector.getLength(); + return vector.start + vector.stride * index; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromIntAccess SLOW_PATH_ACCESS = new SlowPathFromIntAccess() { + @Override + protected int getInt(Object store, int index) { + RIntSequence vector = (RIntSequence) store; + assert index >= 0 && index < vector.getLength(); + return vector.start + vector.stride * index; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java index f52c7cb614b01d9554536c7e2ee6c1618ffc13f4..17a03fc109ffdb06804919ad7e20376ae49d0f08 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RIntVector.java @@ -29,8 +29,12 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.ops.na.NACheck; public final class RIntVector extends RVector<int[]> implements RAbstractIntVector { @@ -40,7 +44,7 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect RIntVector(int[] data, boolean complete) { super(complete); this.data = data; - assert verify(); + assert RAbstractVector.verify(this); } RIntVector(int[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { @@ -99,6 +103,10 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect NativeDataAccess.setData(this, (int[]) store, index, value); } + public void setDataAt(int index, int value) { + NativeDataAccess.setData(this, data, index, value); + } + @Override protected RIntVector internalCopy() { if (data != null) { @@ -126,23 +134,6 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect return NativeDataAccess.getDataLength(this, data); } - @Override - public String toString() { - return toString(i -> Double.toString(getDataAt(i))); - } - - @Override - public boolean verify() { - if (isComplete()) { - for (int i = 0; i < getLength(); i++) { - if (RRuntime.isNA(getDataAt(i))) { - return false; - } - } - } - return true; - } - @Override public int[] getDataCopy() { if (data != null) { @@ -246,4 +237,49 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect complete = false; } } + + private static final class FastPathAccess extends FastPathFromIntAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected int getInt(Object store, int index) { + return hasStore ? ((int[]) store)[index] : NativeDataAccess.getIntNativeMirrorData(store, index); + } + + @Override + protected void setInt(Object store, int index, int value) { + if (hasStore) { + ((int[]) store)[index] = value; + } else { + NativeDataAccess.setNativeMirrorIntData(store, index, value); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromIntAccess SLOW_PATH_ACCESS = new SlowPathFromIntAccess() { + @Override + protected int getInt(Object store, int index) { + RIntVector vector = (RIntVector) store; + return NativeDataAccess.getData(vector, vector.data, index); + } + + @Override + protected void setInt(Object store, int index, int value) { + RIntVector vector = (RIntVector) store; + NativeDataAccess.setData(vector, vector.data, index, value); + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java index eb0ea1f399ffd83e2dd88f286e7ec133c0467735..0eed431c3a623f0eecd166befaf467d24f241caa 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteger.java @@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; @ValueType public final class RInteger extends RScalarVector implements RAbstractIntVector { @@ -95,4 +99,35 @@ public final class RInteger extends RScalarVector implements RAbstractIntVector public boolean isNA() { return RRuntime.isNA(value); } + + private static final class FastPathAccess extends FastPathFromIntAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected int getInt(Object store, int index) { + assert index == 0; + return ((RInteger) store).value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromIntAccess SLOW_PATH_ACCESS = new SlowPathFromIntAccess() { + @Override + protected int getInt(Object store, int index) { + assert index == 0; + return ((RInteger) store).value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java index 7fa8714d7a91980ce6aa176867b37e4e7bbedcef..43c77e0ca59aaf0dfc848b1af457ee091a24d531 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLanguage.java @@ -30,6 +30,9 @@ import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.nodes.RBaseNode; /** @@ -76,6 +79,11 @@ public final class RLanguage extends RSharingAttributeStorage implements RAbstra this.length = length; } + @Override + public Object getInternalStore() { + return this; + } + @TruffleBoundary public static Object fromList(Object o, RLanguage.RepType type) { RList l; @@ -276,4 +284,45 @@ public final class RLanguage extends RSharingAttributeStorage implements RAbstra private void setNamesOnPairList(RStringVector names) { list.setNames(names); } + + private static final class FastPathAccess extends FastPathFromListAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + public RType getType() { + return RType.Language; + } + + @TruffleBoundary + @Override + protected Object getListElement(Object store, int index) { + return ((RLanguage) store).getDataAtAsObject(index); + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() { + @Override + public RType getType() { + return RType.Language; + } + + @TruffleBoundary + @Override + protected Object getListElement(Object store, int index) { + return ((RLanguage) store).getDataAtAsObject(index); + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java index 650c2f1173a80e6c7cf1f3b8dd5c56724421af39..ee3847e78bdd6e922630eb9882c3f90b42138ccd 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RList.java @@ -25,7 +25,12 @@ package com.oracle.truffle.r.runtime.data; import java.util.Arrays; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; public final class RList extends RListBase implements RAbstractListVector { @@ -83,4 +88,53 @@ public final class RList extends RListBase implements RAbstractListVector { protected RList internalCopyResized(int size, boolean fillNA, int[] dimensions) { return RDataFactory.createList(copyResizedData(size, fillNA), dimensions); } + + private static final class FastPathAccess extends FastPathFromListAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + public RType getType() { + return RType.List; + } + + @Override + protected Object getListElement(Object store, int index) { + return ((Object[]) store)[index]; + } + + @Override + protected void setListElement(Object store, int index, Object value) { + ((Object[]) store)[index] = value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() { + @Override + public RType getType() { + return RType.List; + } + + @Override + protected Object getListElement(Object store, int index) { + return ((RList) store).data[index]; + } + + @Override + protected void setListElement(Object store, int index, Object value) { + ((RList) store).data[index] = value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java index 4538d1a4eecf854ffb1c05ef26e8c24113e292dc..f672375dec1e61b7580f9ab933f1256fa133365f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RListBase.java @@ -24,7 +24,6 @@ package com.oracle.truffle.r.runtime.data; import java.util.Arrays; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.model.RAbstractListBaseVector; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; @@ -53,7 +52,7 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi RListBase(Object[] data) { super(false); this.data = data; - assert verify(); + assert RAbstractVector.verify(this); } RListBase(Object[] data, int[] dims, RStringVector names, RList dimNames) { @@ -94,21 +93,6 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi ((Object[]) store)[index] = value; } - @Override - public String toString() { - return toString(i -> RRuntime.toString(getDataAt(i))); - } - - @Override - public final boolean verify() { - for (Object item : data) { - if (item == null) { - return false; - } - } - return true; - } - @Override public Object[] getInternalManagedData() { return data; @@ -193,11 +177,6 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi return newData; } - @Override - public final boolean checkCompleteness() { - return true; - } - @Override public final void setElement(int i, Object value) { data[i] = value; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java index 7fade92f1bed1c2e7ebb42f3232d09a46e5c6184..c65961c55e9121c34a77f6b614b249cec3fbe78f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogical.java @@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromLogicalAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromLogicalAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; @ValueType public final class RLogical extends RScalarVector implements RAbstractLogicalVector { @@ -105,4 +109,35 @@ public final class RLogical extends RScalarVector implements RAbstractLogicalVec public static boolean isValid(byte left) { return left == RRuntime.LOGICAL_NA || left == RRuntime.LOGICAL_FALSE || left == RRuntime.LOGICAL_TRUE; } + + private static final class FastPathAccess extends FastPathFromLogicalAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected byte getLogical(Object store, int index) { + assert index == 0; + return ((RLogical) store).value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromLogicalAccess SLOW_PATH_ACCESS = new SlowPathFromLogicalAccess() { + @Override + protected byte getLogical(Object store, int index) { + assert index == 0; + return ((RLogical) store).value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java index 1d5bcca0900342eac04e280970e601c77d90ab45..8e097a7a97a430f0e34301f0e884ae43b44e47d4 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RLogicalVector.java @@ -29,8 +29,12 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromLogicalAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromLogicalAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.ops.na.NACheck; public final class RLogicalVector extends RVector<byte[]> implements RAbstractLogicalVector { @@ -40,7 +44,7 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo RLogicalVector(byte[] data, boolean complete) { super(complete); this.data = data; - assert verify(); + assert RAbstractVector.verify(this); } RLogicalVector(byte[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { @@ -95,6 +99,10 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo NativeDataAccess.setData(this, (byte[]) store, index, value); } + public void setDataAt(int index, byte value) { + NativeDataAccess.setData(this, data, index, value); + } + @Override public byte getDataAt(Object store, int index) { assert data == store; @@ -128,23 +136,6 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo return NativeDataAccess.getDataLength(this, data); } - @Override - public String toString() { - return toString(i -> RRuntime.logicalToString(getDataAt(i))); - } - - @Override - public boolean verify() { - if (isComplete()) { - for (int i = 0; i < getLength(); i++) { - if (RRuntime.isNA(getDataAt(i))) { - return false; - } - } - } - return true; - } - @Override public byte getDataAt(int index) { return NativeDataAccess.getData(this, data, index); @@ -249,4 +240,49 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo } return result; } + + private static final class FastPathAccess extends FastPathFromLogicalAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected byte getLogical(Object store, int index) { + return hasStore ? ((byte[]) store)[index] : NativeDataAccess.getLogicalNativeMirrorData(store, index); + } + + @Override + protected void setLogical(Object store, int index, byte value) { + if (hasStore) { + ((byte[]) store)[index] = value; + } else { + NativeDataAccess.setNativeMirrorLogicalData(store, index, value); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromLogicalAccess SLOW_PATH_ACCESS = new SlowPathFromLogicalAccess() { + @Override + protected byte getLogical(Object store, int index) { + RLogicalVector vector = (RLogicalVector) store; + return NativeDataAccess.getData(vector, vector.data, index); + } + + @Override + protected void setLogical(Object store, int index, byte value) { + RLogicalVector vector = (RLogicalVector) store; + NativeDataAccess.setData(vector, vector.data, index, value); + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java index 18c853f56ae813bcfb2153c521b1464929092fea..74765b994d27f012599f7653a36f5f8db5e39810 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPairList.java @@ -33,6 +33,9 @@ import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.gnur.SEXPTYPE; /** @@ -73,6 +76,11 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra this.type = type; } + @Override + public Object getInternalStore() { + return this; + } + /** * Creates a new pair list of given size > 0. Note: pair list of size 0 is NULL. */ @@ -375,4 +383,45 @@ public final class RPairList extends RSharingAttributeStorage implements RAbstra } }; } + + private static final class FastPathAccess extends FastPathFromListAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + public RType getType() { + return RType.PairList; + } + + @TruffleBoundary + @Override + protected Object getListElement(Object store, int index) { + return ((RPairList) store).getDataAtAsObject(index); + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() { + @Override + public RType getType() { + return RType.PairList; + } + + @TruffleBoundary + @Override + protected Object getListElement(Object store, int index) { + return ((RPairList) store).getDataAtAsObject(index); + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java index ff3e3945beeb59beec24ff488c600d602b59aebd..78808abfca7c4d1c410787da6ae0c80777d1c473 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRaw.java @@ -26,8 +26,12 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromRawAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromRawAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; @ValueType public final class RRaw extends RScalarVector implements RAbstractRawVector { @@ -55,7 +59,7 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector { case Complex: return RComplex.valueOf(value, 0.0); case Character: - return RString.valueOf(RRuntime.rawToString(value)); + return RString.valueOf(RRuntime.rawToHexString(value)); default: return null; } @@ -99,4 +103,35 @@ public final class RRaw extends RScalarVector implements RAbstractRawVector { public static RRaw valueOf(byte value) { return new RRaw(value); } + + private static final class FastPathAccess extends FastPathFromRawAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected byte getRaw(Object store, int index) { + assert index == 0; + return ((RRaw) store).value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromRawAccess SLOW_PATH_ACCESS = new SlowPathFromRawAccess() { + @Override + protected byte getRaw(Object store, int index) { + assert index == 0; + return ((RRaw) store).value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java index 97c9435c9d9db82394bd52be2eecdec1222a3d35..8da699c972bc7448564d0178c33d9e7079b15c40 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RRawVector.java @@ -25,12 +25,15 @@ package com.oracle.truffle.r.runtime.data; import java.util.Arrays; import com.oracle.truffle.api.profiles.ConditionProfile; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromRawAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromRawAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.ops.na.NACheck; public final class RRawVector extends RVector<byte[]> implements RAbstractRawVector { @@ -40,7 +43,7 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec RRawVector(byte[] data) { super(true); this.data = data; - assert verify(); + assert RAbstractVector.verify(this); } RRawVector(byte[] data, int[] dims, RStringVector names, RList dimNames) { @@ -92,18 +95,16 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec return NativeDataAccess.getData(this, data, index); } - @Override - public byte getRawDataAt(Object store, int index) { - assert data == store; - return NativeDataAccess.getData(this, (byte[]) store, index); - } - @Override public void setRawDataAt(Object store, int index, byte value) { assert data == store; NativeDataAccess.setData(this, (byte[]) store, index, value); } + public void setRawDataAt(int index, byte value) { + NativeDataAccess.setData(this, data, index, value); + } + @Override protected RRawVector internalCopy() { if (data != null) { @@ -118,16 +119,6 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec return NativeDataAccess.getDataLength(this, data); } - @Override - public String toString() { - return toString(i -> RRuntime.rawToString(getRawDataAt(i))); - } - - @Override - public boolean verify() { - return true; - } - @Override public byte[] getDataCopy() { if (data != null) { @@ -202,4 +193,49 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec complete = false; } } + + private static final class FastPathAccess extends FastPathFromRawAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected byte getRaw(Object store, int index) { + return hasStore ? ((byte[]) store)[index] : NativeDataAccess.getRawNativeMirrorData(store, index); + } + + @Override + protected void setRaw(Object store, int index, byte value) { + if (hasStore) { + ((byte[]) store)[index] = value; + } else { + NativeDataAccess.setNativeMirrorRawData(store, index, value); + } + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromRawAccess SLOW_PATH_ACCESS = new SlowPathFromRawAccess() { + @Override + protected byte getRaw(Object store, int index) { + RRawVector vector = (RRawVector) store; + return NativeDataAccess.getData(vector, vector.data, index); + } + + @Override + protected void setRaw(Object store, int index, byte value) { + RRawVector vector = (RRawVector) store; + NativeDataAccess.setData(vector, vector.data, index, value); + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarList.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarList.java index 1ea23adc66f510252e67c8aa0696a03e7e9d2993..044cdffb584ff280fe20b971d3ea9e221d69da8e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarList.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarList.java @@ -25,8 +25,12 @@ package com.oracle.truffle.r.runtime.data; import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; @ValueType public final class RScalarList extends RScalarVector implements RAbstractListVector { @@ -87,4 +91,45 @@ public final class RScalarList extends RScalarVector implements RAbstractListVec public boolean isNA() { return false; } + + private static final class FastPathAccess extends FastPathFromListAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + public RType getType() { + return RType.List; + } + + @Override + protected Object getListElement(Object store, int index) { + assert index == 0; + return ((RScalarList) store).value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromListAccess SLOW_PATH_ACCESS = new SlowPathFromListAccess() { + @Override + public RType getType() { + return RType.List; + } + + @Override + protected Object getListElement(Object store, int index) { + assert index == 0; + return ((RScalarList) store).value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java index 80f1da3147b21cc03ee8a51ea175c0307f59413c..314b58af2dc90e4c1b3cf5653ab364312bf15f14 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RScalarVector.java @@ -36,6 +36,11 @@ public abstract class RScalarVector extends RScalar implements RAbstractVector { return this; } + @Override + public Object getInternalStore() { + return this; + } + @Override public void setComplete(boolean complete) { // scalar vectors don't need this information. @@ -170,9 +175,4 @@ public abstract class RScalarVector extends RScalar implements RAbstractVector { public boolean isArray() { return false; } - - @Override - public final boolean checkCompleteness() { - return isComplete(); - } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java index d9aa895489f362128e582c828f9161b20a408d2e..f9a75146fe100015669b7696d0c07fe4169de795 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RSequence.java @@ -41,6 +41,11 @@ public abstract class RSequence implements RAbstractVector { this.length = length; } + @Override + public Object getInternalStore() { + return this; + } + @Override public final int getLength() { return length; @@ -60,11 +65,6 @@ public abstract class RSequence implements RAbstractVector { return true; } - @Override - public boolean checkCompleteness() { - return true; - } - @Override public void setComplete(boolean complete) { // sequences are always complete diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java index abf51a343f797352297a0a94155670ef897b5d5b..2929ffb79f3b69310eeb31a2ffe31809f77d46a9 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RString.java @@ -27,8 +27,12 @@ import com.oracle.truffle.api.CompilerDirectives.ValueType; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; 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.FastPathVectorAccess.FastPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; @ValueType public final class RString extends RScalarVector implements RAbstractStringVector { @@ -95,4 +99,35 @@ public final class RString extends RScalarVector implements RAbstractStringVecto throw new AssertionError(); } } + + private static final class FastPathAccess extends FastPathFromStringAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected String getString(Object store, int index) { + assert index == 0; + return ((RString) store).value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromStringAccess SLOW_PATH_ACCESS = new SlowPathFromStringAccess() { + @Override + protected String getString(Object store, int index) { + assert index == 0; + return ((RString) store).value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java index ee79af03a47bf35cf4c2b2577b3f09edbcedf22d..220df129745921d88f447758b9b1d0d2a1274d9f 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringSequence.java @@ -29,10 +29,14 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; 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.FastPathVectorAccess.FastPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; -public class RStringSequence extends RSequence implements RAbstractStringVector { +public final class RStringSequence extends RSequence implements RAbstractStringVector { private final int start; private final int stride; @@ -168,4 +172,37 @@ public class RStringSequence extends RSequence implements RAbstractStringVector CompilerAsserts.neverPartOfCompilation(); return "[\"" + getStartObject() + "\" - \"" + prefix + getEnd() + suffix + "\"]"; } + + private static final class FastPathAccess extends FastPathFromStringAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected String getString(Object store, int index) { + RStringSequence vector = (RStringSequence) store; + assert index >= 0 && index < vector.getLength(); + return vector.prefix + (vector.start + vector.stride * index) + vector.suffix; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromStringAccess SLOW_PATH_ACCESS = new SlowPathFromStringAccess() { + @Override + protected String getString(Object store, int index) { + RStringSequence vector = (RStringSequence) store; + assert index >= 0 && index < vector.getLength(); + return vector.prefix + (vector.start + vector.stride * index) + vector.suffix; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java index 4a0374063a3f362a75d02fbbc2c91ba40a57a5b0..ee59d39da0552ac2d5483e9b28c762e12bbbfcf0 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RStringVector.java @@ -30,8 +30,12 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.data.closures.RClosures; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; 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.FastPathVectorAccess.FastPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; import com.oracle.truffle.r.runtime.ops.na.NACheck; public final class RStringVector extends RVector<String[]> implements RAbstractStringVector { @@ -41,7 +45,7 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS RStringVector(String[] data, boolean complete) { super(complete); this.data = data; - assert verify(); + assert RAbstractVector.verify(this); } RStringVector(String[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { @@ -78,6 +82,10 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS ((String[]) store)[index] = value; } + public void setDataAt(int index, String value) { + data[index] = value; + } + @Override public String getDataAt(Object store, int index) { assert data == store; @@ -119,23 +127,6 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS return data; } - @Override - public String toString() { - return toString(i -> getDataAt(i)); - } - - @Override - public boolean verify() { - if (isComplete()) { - for (String b : data) { - if (b == RRuntime.STRING_NA) { - return false; - } - } - } - return true; - } - @Override public String getDataAt(int i) { return data[i]; @@ -219,4 +210,45 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS public void setElement(int i, Object value) { data[i] = (String) value; } + + private static final class FastPathAccess extends FastPathFromStringAccess { + + FastPathAccess(RAbstractContainer value) { + super(value); + } + + @Override + protected String getString(Object store, int index) { + assert hasStore; + return ((String[]) store)[index]; + } + + @Override + protected void setString(Object store, int index, String value) { + assert hasStore; + ((String[]) store)[index] = value; + } + } + + @Override + public VectorAccess access() { + return new FastPathAccess(this); + } + + private static final SlowPathFromStringAccess SLOW_PATH_ACCESS = new SlowPathFromStringAccess() { + @Override + protected String getString(Object store, int index) { + return ((RStringVector) store).data[index]; + } + + @Override + protected void setString(Object store, int index, String value) { + ((RStringVector) store).data[index] = value; + } + }; + + @Override + public VectorAccess slowPathAccess() { + return SLOW_PATH_ACCESS; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java index f11da3d123650f52a9ed9c974c93284153ae10de..582b9366c70bc6a0cdd69ba8e82cba861b652241 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java @@ -109,21 +109,11 @@ public class RTypes { return RDataFactory.createDoubleVectorFromScalar(value); } - @ImplicitCast - public static RAbstractContainer toAbstractContainer(RRaw value) { - return RDataFactory.createRawVectorFromScalar(value); - } - @ImplicitCast public static RAbstractContainer toAbstractContainer(byte value) { return RDataFactory.createLogicalVectorFromScalar(value); } - @ImplicitCast - public static RAbstractContainer toAbstractContainer(RComplex value) { - return RDataFactory.createComplexVectorFromScalar(value); - } - @ImplicitCast public static RAbstractContainer toAbstractContainer(String value) { return RDataFactory.createStringVectorFromScalar(value); @@ -139,21 +129,11 @@ public class RTypes { return RDataFactory.createDoubleVectorFromScalar(value); } - @ImplicitCast - public static RAbstractVector toAbstractVector(RRaw value) { - return RDataFactory.createRawVectorFromScalar(value); - } - @ImplicitCast public static RAbstractVector toAbstractVector(byte value) { return RDataFactory.createLogicalVectorFromScalar(value); } - @ImplicitCast - public static RAbstractVector toAbstractVector(RComplex value) { - return RDataFactory.createComplexVectorFromScalar(value); - } - @ImplicitCast public static RAbstractVector toAbstractVector(String value) { return RDataFactory.createStringVectorFromScalar(value); @@ -169,21 +149,11 @@ public class RTypes { return RDataFactory.createDoubleVectorFromScalar(value); } - @ImplicitCast - public static RAbstractComplexVector toAbstractComplexVector(RComplex vector) { - return RDataFactory.createComplexVectorFromScalar(vector); - } - @ImplicitCast public static RAbstractLogicalVector toAbstractLogicalVector(byte vector) { return RDataFactory.createLogicalVectorFromScalar(vector); } - @ImplicitCast - public static RAbstractRawVector toAbstractRawVector(RRaw vector) { - return RDataFactory.createRawVectorFromScalar(vector); - } - @ImplicitCast public static RAbstractStringVector toAbstractStringVector(String vector) { return RDataFactory.createStringVectorFromScalar(vector); @@ -199,21 +169,11 @@ public class RTypes { return RDataFactory.createDoubleVectorFromScalar(value); } - @ImplicitCast - public static RAbstractAtomicVector toAbstractAtomicVector(RRaw value) { - return RDataFactory.createRawVectorFromScalar(value); - } - @ImplicitCast public static RAbstractAtomicVector toAbstractAtomicVector(byte value) { return RDataFactory.createLogicalVectorFromScalar(value); } - @ImplicitCast - public static RAbstractAtomicVector toAbstractAtomicVector(RComplex value) { - return RDataFactory.createComplexVectorFromScalar(value); - } - @ImplicitCast public static RAbstractAtomicVector toAbstractAtomicVector(String value) { return RDataFactory.createStringVectorFromScalar(value); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java index 5f7239c993e84846c1d3b7a57d589b66788301e5..2e2b076c975bf3fb8b2bf88d6582cc73b76c82a2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RVector.java @@ -24,8 +24,6 @@ package com.oracle.truffle.r.runtime.data; import static com.oracle.truffle.r.runtime.RError.NO_CALLER; -import java.util.function.Function; - import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -33,13 +31,14 @@ import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.SuppressFBWarnings; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; 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.GetReadonlyData; +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.nodes.RBaseNode; import com.oracle.truffle.r.runtime.ops.na.NACheck; @@ -59,9 +58,6 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck; */ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implements RAbstractVector, RFFIAccess { - private static final RStringVector implicitClassHeaderArray = RDataFactory.createStringVector(new String[]{RType.Array.getName()}, true); - private static final RStringVector implicitClassHeaderMatrix = RDataFactory.createStringVector(new String[]{RType.Matrix.getName()}, true); - protected boolean complete; // "complete" means: does not contain NAs protected RVector(boolean complete) { @@ -140,7 +136,7 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement @Override public final void setComplete(boolean complete) { this.complete = complete; - assert verify(); + assert RAbstractVector.verify(this); } private void removeAttributeMapping(String key) { @@ -537,8 +533,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement protected abstract RVector<ArrayT> internalCopy(); - public abstract boolean verify(); - /** * Update a data item in the vector. Possibly not as efficient as type-specific methods, but in * some cases it likely does not matter (e.g. if used alongside I/O operations). @@ -607,50 +601,52 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement * Inits dims, names and dimnames attributes and it should only be invoked if no attributes were * initialized yet. */ - @TruffleBoundary - protected final void initDimsNamesDimNames(int[] dimensions, RStringVector names, RList dimNames) { + final void initDimsNamesDimNames(int[] dimensions, RStringVector names, RList dimNames) { assert (this.attributes == null) : "Vector attributes must be null"; assert names != this; assert dimNames != this; + assert names == null || names.getLength() == getLength() : "size mismatch: names.length=" + names.getLength() + " vs. length=" + getLength(); + initAttributes(createAttributes(dimensions, names, dimNames)); + } + + @TruffleBoundary + static DynamicObject createAttributes(int[] dimensions, RStringVector names, RList dimNames) { if (dimNames != null) { - DynamicObject attrs; if (dimensions != null) { RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true); - attrs = RAttributesLayout.createDimAndDimNames(dimensionsVector, dimNames); // one-dimensional arrays do not have names, only dimnames with one value so do not // init names in that case if (names != null && dimensions.length != 1) { - assert names.getLength() == getLength() : "size mismatch: names.length=" + names.getLength() + " vs. length=" + getLength(); - attrs.define(RRuntime.NAMES_ATTR_KEY, names); + return RAttributesLayout.createNamesAndDimAndDimNames(names, dimensionsVector, dimNames); + } else { + return RAttributesLayout.createDimAndDimNames(dimensionsVector, dimNames); } } else { - attrs = RAttributesLayout.createDimNames(dimNames); if (names != null) { - assert names.getLength() == getLength() : "size mismatch: names.length=" + names.getLength() + " vs. length=" + getLength(); - attrs.define(RRuntime.NAMES_ATTR_KEY, names); + return RAttributesLayout.createNamesAndDimNames(names, dimNames); + } else { + return RAttributesLayout.createDimNames(dimNames); } } - initAttributes(attrs); } else { - if (names != null) { - // since this constructor is for internal use only, the assertion shouldn't fail - assert names.getLength() == getLength() : "size mismatch: " + names.getLength() + " vs. " + getLength(); - if (dimensions != null) { - RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true); + if (dimensions != null) { + RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true); + if (names != null) { if (dimensions.length != 1) { - initAttributes(RAttributesLayout.createNamesAndDim(names, dimensionsVector)); + return RAttributesLayout.createNamesAndDim(names, dimensionsVector); } else { // one-dimensional arrays do not have names, only dimnames with one value RList newDimNames = RDataFactory.createList(new Object[]{names}); - initAttributes(RAttributesLayout.createDimAndDimNames(dimensionsVector, newDimNames)); + return RAttributesLayout.createDimAndDimNames(dimensionsVector, newDimNames); } } else { - initAttributes(RAttributesLayout.createNames(names)); + return RAttributesLayout.createDim(dimensionsVector); } } else { - if (dimensions != null) { - RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true); - initAttributes(RAttributesLayout.createDim(dimensionsVector)); + if (names != null) { + return RAttributesLayout.createNames(names); + } else { + return null; } } } @@ -749,18 +745,6 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement } } - // As shape of the vector may change at run-time we need to compute - // class hierarchy on the fly. - protected final RStringVector getClassHierarchyHelper(RStringVector implicitClassHeader) { - if (isMatrix()) { - return implicitClassHeaderMatrix; - } - if (isArray()) { - return implicitClassHeaderArray; - } - return implicitClassHeader; - } - public static void verifyDimensions(int vectorLength, int[] newDimensions, RBaseNode invokingNode) { int length = 1; for (int i = 0; i < newDimensions.length; i++) { @@ -778,18 +762,25 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement private static final int MAX_TOSTRING_LENGTH = 100; - protected final String toString(Function<Integer, String> element) { + @Override + public final String toString() { CompilerAsserts.neverPartOfCompilation(); StringBuilder str = new StringBuilder("["); - for (int i = 0; i < getLength(); i++) { - if (i > 0) { - str.append(", "); - } - str.append(element.apply(i)); - if (str.length() > MAX_TOSTRING_LENGTH - 1) { - str.setLength(MAX_TOSTRING_LENGTH - 4); - str.append("..."); - break; + VectorAccess access = slowPathAccess(); + try (SequentialIterator iter = access.access(this)) { + if (access.next(iter)) { + while (true) { + str.append(access.getType().isAtomic() ? access.getString(iter) : access.getListElement(iter).toString()); + if (!access.next(iter)) { + break; + } + str.append(", "); + if (str.length() > MAX_TOSTRING_LENGTH - 1) { + str.setLength(MAX_TOSTRING_LENGTH - 4); + str.append("..."); + break; + } + } } } return str.append(']').toString(); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java index e8c5104485f640935efc3d2ff41c6c78bae2f052..7495f52ae81abb5793ecb327fd2aa960d8661454 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/closures/RToVectorClosure.java @@ -24,6 +24,7 @@ package com.oracle.truffle.r.runtime.data.closures; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.ConditionProfile; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -31,6 +32,7 @@ import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; abstract class RToVectorClosure implements RAbstractVector { @@ -49,8 +51,8 @@ abstract class RToVectorClosure implements RAbstractVector { } @Override - public EmptyInternalStore getInternalStore() { - return EmptyInternalStore.INSTANCE; + public Object getInternalStore() { + return this; } @Override @@ -184,4 +186,14 @@ abstract class RToVectorClosure implements RAbstractVector { // first materialize and then cast and do not create a closure over a closure. return materialize().castSafe(type, isNAProfile, keepAttrs); } + + @Override + public final VectorAccess access() { + throw RInternalError.shouldNotReachHere("access() for " + getClass().getSimpleName()); + } + + @Override + public final VectorAccess slowPathAccess() { + throw RInternalError.shouldNotReachHere("slowPathAccess() for " + getClass().getSimpleName()); + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java index b2d9e6cd06d0ad7e508393bfe0f29004d3e6f8f4..930526998fc0672d6b855b6ff55be175aafc5399 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractComplexVector.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.runtime.data.model; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RComplexVector; @@ -36,10 +35,6 @@ public interface RAbstractComplexVector extends RAbstractAtomicVector { RComplex getDataAt(int index); - default RComplex getDataAt(@SuppressWarnings("unused") Object store, int index) { - return getDataAt(index); - } - @Override RComplexVector materialize(); @@ -48,16 +43,6 @@ public interface RAbstractComplexVector extends RAbstractAtomicVector { throw new UnsupportedOperationException(); } - @Override - default boolean checkCompleteness() { - for (int i = 0; i < getLength(); i++) { - if (RRuntime.isNA(getDataAt(i))) { - return false; - } - } - return true; - } - @Override default RType getRType() { return RType.Complex; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java index 8723bed3da30a69e05f8e1f9405bcaf65a9ca798..93742f57b50b9c830d70599ccadaef1f576228c2 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractContainer.java @@ -28,6 +28,7 @@ import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RTypedValue; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; public interface RAbstractContainer extends RAttributable, RTypedValue { @@ -67,9 +68,7 @@ public interface RAbstractContainer extends RAttributable, RTypedValue { * vector's fields, but instead read the necessary data from a local variable, which could be * beneficial when in loop. */ - default Object getInternalStore() { - return EmptyInternalStore.INSTANCE; - } + Object getInternalStore(); default RStringVector getNames() { CompilerAsserts.neverPartOfCompilation(); @@ -101,10 +100,7 @@ public interface RAbstractContainer extends RAttributable, RTypedValue { setAttr(RRuntime.ROWNAMES_ATTR_KEY, rowNames); } - final class EmptyInternalStore { - private EmptyInternalStore() { - } + VectorAccess access(); - public static final EmptyInternalStore INSTANCE = new EmptyInternalStore(); - } + VectorAccess slowPathAccess(); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java index ab8c782a3f97d0e8882eb8d551d50debf22905f0..c223c64054322e529a90b95aa7604c89c0cd24e7 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractDoubleVector.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.runtime.data.model; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RDoubleVector; @@ -47,16 +46,6 @@ public interface RAbstractDoubleVector extends RAbstractAtomicVector { @Override RDoubleVector materialize(); - @Override - default boolean checkCompleteness() { - for (int i = 0; i < getLength(); i++) { - if (RRuntime.isNA(getDataAt(i))) { - return false; - } - } - return true; - } - @Override default RType getRType() { return RType.Double; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java index 92401aea21e6a7f5a42f0c130ab62b3c716806ce..727f43772b68078cd1061ee364a1c6185a5ffabb 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractIntVector.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.runtime.data.model; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RIntVector; @@ -47,16 +46,6 @@ public interface RAbstractIntVector extends RAbstractAtomicVector { @Override RIntVector materialize(); - @Override - default boolean checkCompleteness() { - for (int i = 0; i < getLength(); i++) { - if (RRuntime.isNA(getDataAt(i))) { - return false; - } - } - return true; - } - @Override default RType getRType() { return RType.Integer; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java index ea019fe0a4d23b6cd5a43837a78d79f5b1095925..e6f99db40e80746821447236403f97d8655b4315 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractListBaseVector.java @@ -35,9 +35,4 @@ public interface RAbstractListBaseVector extends RAbstractVector { default void setDataAt(Object store, int index, Object value) { throw new UnsupportedOperationException(); } - - @Override - default boolean checkCompleteness() { - return true; - } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java index 2a1c503de5361dcd250c061344b5c621f97c0e8a..ff0ac5f5732aa924f1c6e86a7b4da6e2079d1dd6 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractLogicalVector.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.runtime.data.model; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RLogicalVector; @@ -47,16 +46,6 @@ public interface RAbstractLogicalVector extends RAbstractAtomicVector { @Override RLogicalVector materialize(); - @Override - default boolean checkCompleteness() { - for (int i = 0; i < getLength(); i++) { - if (RRuntime.isNA(getDataAt(i))) { - return false; - } - } - return true; - } - @Override default RType getRType() { return RType.Logical; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java index 5f8697e39d73b98504936405749183fdf25dd57d..f76d746806f59a662716945e38833fe32abe671c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractRawVector.java @@ -33,10 +33,6 @@ public interface RAbstractRawVector extends RAbstractAtomicVector { return RRaw.valueOf(getRawDataAt(index)); } - default byte getRawDataAt(@SuppressWarnings("unused") Object store, int index) { - return getRawDataAt(index); - } - @SuppressWarnings("unused") default void setRawDataAt(Object store, int index, byte value) { throw new UnsupportedOperationException(); @@ -47,11 +43,6 @@ public interface RAbstractRawVector extends RAbstractAtomicVector { @Override RRawVector materialize(); - @Override - default boolean checkCompleteness() { - return true; - } - @Override default RType getRType() { return RType.Raw; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java index af93f141e09f2791c2e7fcc4b809b2302ce22355..c6e5f960d14c5c54ded61a751aef5c19cc2d46a8 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractStringVector.java @@ -22,7 +22,6 @@ */ package com.oracle.truffle.r.runtime.data.model; -import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -47,16 +46,6 @@ public interface RAbstractStringVector extends RAbstractAtomicVector { @Override RStringVector materialize(); - @Override - default boolean checkCompleteness() { - for (int i = 0; i < getLength(); i++) { - if (RRuntime.isNA(getDataAt(i))) { - return false; - } - } - return true; - } - @Override default RType getRType() { return RType.Character; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java index e5fe39c6a8072bf343a0f169dfe81af770a1acd1..43039d80a1facd3c392b8cf758a7f46f97081d96 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/model/RAbstractVector.java @@ -22,10 +22,13 @@ */ package com.oracle.truffle.r.runtime.data.model; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.MemoryCopyTracer; import com.oracle.truffle.r.runtime.data.RVector; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; /** * When implementing, make sure to invoke related {@link MemoryCopyTracer} methods. @@ -62,8 +65,6 @@ public interface RAbstractVector extends RAbstractContainer { boolean isArray(); - boolean checkCompleteness(); - /** * Casts a vector to another {@link RType}. If a safe cast to the target {@link RType} is not * supported <code>null</code> is returned. Instead of materializing the cast for each index the @@ -99,4 +100,31 @@ public interface RAbstractVector extends RAbstractContainer { } void setComplete(boolean complete); + + /** + * Verifies the integrity of the vector, mainly whether a vector that claims to be + * {@link #isComplete()} contains NA values. + */ + static boolean verify(RAbstractVector vector) { + CompilerAsserts.neverPartOfCompilation(); + VectorAccess access = vector.slowPathAccess(); + assert access.getType().isVector(); + if (!access.getType().isAtomic()) { + // check non-atomic vectors for nullness + try (SequentialIterator iter = access.access(vector)) { + while (access.next(iter)) { + assert access.getListElement(iter) != null : "element " + iter.getIndex() + " of vector " + vector + " is null"; + } + } + } + if (vector.isComplete()) { + // check all vectors for completeness + try (SequentialIterator iter = access.access(vector)) { + while (access.next(iter)) { + assert !access.isNA(iter) : "element " + iter.getIndex() + " of vector " + vector + " is NA"; + } + } + } + return true; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/EnableNACheckNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/EnableNACheckNode.java deleted file mode 100644 index d9884dc6260054d5f0cca9fcb034a26bd53f4457..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/EnableNACheckNode.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; -import com.oracle.truffle.r.runtime.ops.na.NACheck; - -public abstract class EnableNACheckNode extends Node { - public abstract void execute(NACheck check, RAbstractVector vector); - - public static EnableNACheckNode create() { - return EnableNACheckNodeGen.create(); - } - - @Specialization(guards = "vector.getClass() == clazz", limit = "10") - public void doEnable(NACheck check, RAbstractVector vector, - @Cached("vector.getClass()") Class<? extends RAbstractVector> clazz) { - check.enable(clazz.cast(vector)); - } - - @Specialization(replaces = "doEnable") - public void doEnableGeneric(NACheck check, RAbstractVector vector) { - check.enable(vector); - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/FastPathVectorAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/FastPathVectorAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..4d8948d3f6913035d3a0c070767e2f138e3f0ab3 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/FastPathVectorAccess.java @@ -0,0 +1,635 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data.nodes; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RComplex; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RRaw; +import com.oracle.truffle.r.runtime.data.RVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; + +/** + * Base classes for {@link VectorAccess} implementations that are used on the fast path. For + * implementation reasons, most of this code is mirrored in {@link SlowPathVectorAccess}, so that + * any changes need to be mirrored there. + */ +public abstract class FastPathVectorAccess extends VectorAccess { + + protected boolean naReported; // TODO: move this into the iterator + + protected FastPathVectorAccess(Object value) { + super(value.getClass(), value instanceof RAbstractContainer ? ((RAbstractContainer) value).getInternalStore() != null : true); + } + + @Override + protected final Object getStore(RAbstractContainer vector) { + return hasStore ? vector.getInternalStore() : ((RVector<?>) vector).getNativeMirror(); + } + + protected final void warning(RError.Message message) { + CompilerAsserts.neverPartOfCompilation(); + if (!naReported) { + RError.warning(RError.SHOW_CALLER, message); + naReported = true; + } + } + + public abstract static class FastPathFromIntAccess extends FastPathVectorAccess { + + public FastPathFromIntAccess(Object value) { + super(value); + } + + @Override + public final RType getType() { + return RType.Integer; + } + + @Override + protected final double getDouble(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.DOUBLE_NA : RRuntime.int2doubleNoCheck(value); + } + + @Override + protected final byte getRaw(Object store, int index) { + int value = getInt(store, index); + byte result = (byte) value; + if ((result & 0xff) != value) { + warning(Message.OUT_OF_RANGE); + return 0; + } + return result; + } + + @Override + protected final byte getLogical(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.int2logicalNoCheck(value); + } + + @Override + protected final RComplex getComplex(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RComplex.createNA() : RRuntime.int2complexNoCheck(value); + } + + @Override + protected final double getComplexR(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value; + } + + @Override + protected final double getComplexI(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0; + } + + @Override + protected final String getString(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.STRING_NA : RRuntime.intToStringNoCheck(value); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getInt(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setInt(store, index, sourceAccess.getInt(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setInt(store, index, sourceAccess.getInt(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setInt(store, index, RRuntime.INT_NA); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getInt(store, index)); + } + } + + public abstract static class FastPathFromDoubleAccess extends FastPathVectorAccess { + + public FastPathFromDoubleAccess(Object value) { + super(value); + } + + @Override + public final RType getType() { + return RType.Double; + } + + @Override + protected final int getInt(Object store, int index) { + double value = getDouble(store, index); + if (Double.isNaN(value)) { + na.enable(true); + return RRuntime.INT_NA; + } + if (value > Integer.MAX_VALUE || value <= Integer.MIN_VALUE) { + na.enable(true); + warning(Message.NA_INTRODUCED_COERCION_INT); + return RRuntime.INT_NA; + } + return (int) value; + } + + @Override + protected final byte getRaw(Object store, int index) { + int value = (int) getDouble(store, index); + byte result = (byte) value; + if ((result & 0xff) != value) { + warning(Message.OUT_OF_RANGE); + return 0; + } + return result; + } + + @Override + protected final byte getLogical(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.double2logicalNoCheck(value); + } + + @Override + protected final RComplex getComplex(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RComplex.createNA() : RRuntime.double2complexNoCheck(value); + } + + @Override + protected final double getComplexR(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value; + } + + @Override + protected final double getComplexI(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0; + } + + @Override + protected final String getString(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeDouble(value); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getDouble(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setDouble(store, index, sourceAccess.getDouble(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setDouble(store, index, sourceAccess.getDouble(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setDouble(store, index, RRuntime.DOUBLE_NA); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getDouble(store, index)); + } + } + + public abstract static class FastPathFromLogicalAccess extends FastPathVectorAccess { + + public FastPathFromLogicalAccess(Object value) { + super(value); + } + + @Override + public final RType getType() { + return RType.Logical; + } + + @Override + protected final int getInt(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.INT_NA : RRuntime.logical2intNoCheck(value); + } + + @Override + protected final double getDouble(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.DOUBLE_NA : RRuntime.logical2doubleNoCheck(value); + } + + @Override + protected final byte getRaw(Object store, int index) { + byte value = getLogical(store, index); + if (na.check(value)) { + warning(Message.OUT_OF_RANGE); + return 0; + } + return value; + } + + @Override + protected final RComplex getComplex(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RComplex.createNA() : RRuntime.logical2complexNoCheck(value); + } + + @Override + protected final double getComplexR(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value; + } + + @Override + protected final double getComplexI(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0; + } + + @Override + protected final String getString(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.STRING_NA : RRuntime.logicalToStringNoCheck(value); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getLogical(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setLogical(store, index, sourceAccess.getLogical(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setLogical(store, index, sourceAccess.getLogical(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setLogical(store, index, RRuntime.LOGICAL_NA); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getLogical(store, index)); + } + } + + public abstract static class FastPathFromRawAccess extends FastPathVectorAccess { + + public FastPathFromRawAccess(Object value) { + super(value); + } + + @Override + public final RType getType() { + return RType.Raw; + } + + @Override + protected final int getInt(Object store, int index) { + return getRaw(store, index) & 0xff; + } + + @Override + protected final double getDouble(Object store, int index) { + return getRaw(store, index) & 0xff; + } + + @Override + protected final byte getLogical(Object store, int index) { + return getRaw(store, index) == 0 ? RRuntime.LOGICAL_FALSE : RRuntime.LOGICAL_TRUE; + } + + @Override + protected final RComplex getComplex(Object store, int index) { + return RComplex.valueOf(getRaw(store, index) & 0xff, 0); + } + + @Override + protected final double getComplexR(Object store, int index) { + return getRaw(store, index) & 0xff; + } + + @Override + protected final double getComplexI(Object store, int index) { + return 0; + } + + @Override + protected final String getString(Object store, int index) { + return RRuntime.rawToHexString(getRaw(store, index)); + } + + @Override + protected final Object getListElement(Object store, int index) { + return RRaw.valueOf(getRaw(store, index)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setRaw(store, index, sourceAccess.getRaw(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setRaw(store, index, sourceAccess.getRaw(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + /* + * There is no raw NA, but places that write NA for other types usually write 0 for raw. + */ + setRaw(store, index, (byte) 0); + } + + @Override + protected boolean isNA(Object store, int index) { + return false; + } + } + + public abstract static class FastPathFromComplexAccess extends FastPathVectorAccess { + + public FastPathFromComplexAccess(Object value) { + super(value); + } + + @Override + public final RType getType() { + return RType.Complex; + } + + @Override + protected final int getInt(Object store, int index) { + double value = getComplexR(store, index); + if (Double.isNaN(value)) { + na.enable(true); + return RRuntime.INT_NA; + } + if (value > Integer.MAX_VALUE || value <= Integer.MIN_VALUE) { + na.enable(true); + warning(Message.NA_INTRODUCED_COERCION_INT); + return RRuntime.INT_NA; + } + if (getComplexI(store, index) != 0) { + warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION); + } + return (int) value; + } + + @Override + protected final double getDouble(Object store, int index) { + double value = getComplexR(store, index); + if (Double.isNaN(value)) { + na.enable(true); + return RRuntime.DOUBLE_NA; + } + if (getComplexI(store, index) != 0) { + warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION); + } + return value; + } + + @Override + protected final byte getRaw(Object store, int index) { + double value = getComplexR(store, index); + if (Double.isNaN(value) || value < 0 || value >= 256) { + warning(Message.OUT_OF_RANGE); + return 0; + } + if (getComplexI(store, index) != 0) { + warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION); + } + return (byte) value; + } + + @Override + protected final byte getLogical(Object store, int index) { + RComplex value = getComplex(store, index); + return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.complex2logicalNoCheck(value); + } + + @Override + protected final String getString(Object store, int index) { + RComplex value = getComplex(store, index); + return na.check(value) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeComplex(value); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getComplex(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setComplex(store, index, sourceAccess.getComplexR(sourceIter), sourceAccess.getComplexI(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setComplex(store, index, sourceAccess.getComplexR(sourceIter, sourceIndex), sourceAccess.getComplexI(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setComplex(store, index, RRuntime.COMPLEX_NA_REAL_PART, RRuntime.COMPLEX_NA_IMAGINARY_PART); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getComplexR(store, index), getComplexI(store, index)); + } + } + + public abstract static class FastPathFromStringAccess extends FastPathVectorAccess { + + public FastPathFromStringAccess(Object value) { + super(value); + } + + @Override + public final RType getType() { + return RType.Character; + } + + @Override + protected final int getInt(Object store, int index) { + return na.convertStringToInt(getString(store, index)); + } + + @Override + protected final double getDouble(Object store, int index) { + return na.convertStringToDouble(getString(store, index)); + } + + @Override + protected final byte getRaw(Object store, int index) { + int value = na.convertStringToInt(getString(store, index)); + return value >= 0 && value <= 255 ? (byte) value : 0; + } + + @Override + protected final byte getLogical(Object store, int index) { + return na.convertStringToLogical(getString(store, index)); + } + + @Override + protected final RComplex getComplex(Object store, int index) { + return na.convertStringToComplex(getString(store, index)); + } + + @Override + protected final double getComplexR(Object store, int index) { + return na.convertStringToComplex(getString(store, index)).getRealPart(); + } + + @Override + protected final double getComplexI(Object store, int index) { + return na.convertStringToComplex(getString(store, index)).getImaginaryPart(); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getString(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setString(store, index, sourceAccess.getString(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setString(store, index, sourceAccess.getString(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setString(store, index, RRuntime.STRING_NA); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getString(store, index)); + } + } + + public abstract static class FastPathFromListAccess extends FastPathVectorAccess { + + public FastPathFromListAccess(Object value) { + super(value); + } + + @Override + protected final int getInt(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final double getDouble(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final byte getRaw(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final byte getLogical(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final RComplex getComplex(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final double getComplexR(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final double getComplexI(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final String getString(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setListElement(store, index, sourceAccess.getListElement(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setListElement(store, index, sourceAccess.getListElement(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + /* + * There is no list NA, but places that write NA for other types usually write NULL for + * lists. + */ + setListElement(store, index, RNull.instance); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.checkListElement(getListElement(store, index)); + } + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataAt.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataAt.java deleted file mode 100644 index e85b37ebc48af203afdc4afb8bb653f1a103da2e..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataAt.java +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.data.NativeDataAccess; -import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RDoubleSequence; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RIntSequence; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -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.GetDataAtFactory.DoubleNodeGen; -import com.oracle.truffle.r.runtime.data.nodes.GetDataAtFactory.IntNodeGen; - -/** - * Contains nodes implementing fast-path versions of e.g. - * {@link RAbstractIntVector#getDataAt(Object, int)}. The first parameter 'store' should be - * retrieved for given vector using {@link GetDataStore} node. Store object must be used only for - * accessing the data of the vector for which it was created. The reason for having a store object - * is to avoid field load (field of the RVector object) on every data access. - */ -public abstract class GetDataAt extends Node { - - public abstract Object getAsObject(RAbstractVector vector, Object store, int index); - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Int extends GetDataAt { - - public static Int create() { - return IntNodeGen.create(); - } - - @Override - public Object getAsObject(RAbstractVector vector, Object store, int index) { - return get((RAbstractIntVector) vector, store, index); - } - - public final int get(RAbstractIntVector vector, Object store, int index) { - return execute(vector, store, index); - } - - public abstract int execute(RAbstractIntVector vector, Object store, int index); - - protected int doRVector(RIntVector vector, int[] store, int index) { - return store[index]; - } - - @Specialization(guards = "isNativeMirror(store)") - protected int doRVector(RIntVector vector, Object store, int index) { - return NativeDataAccess.getIntNativeMirrorData(store, index); - } - - @Specialization - protected int doSequence(RIntSequence sequence, Object store, int index) { - return sequence.getStart() + index * sequence.getStride(); - } - - // This accounts for other vector types, like closures - @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3") - protected int doGenericCached(RAbstractIntVector vector, Object store, int index, - @Cached("vector.getClass()") Class<? extends RAbstractIntVector> cachedClass) { - return cachedClass.cast(vector).getDataAt(store, index); - } - - @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached") - protected int doGeneric(RAbstractIntVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - @Fallback - protected int doFallback(RAbstractIntVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - protected static boolean isGenericVector(RAbstractIntVector vector) { - return !(vector instanceof RIntVector) && !(vector instanceof RIntSequence); - } - } - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Double extends GetDataAt { - - public static Double create() { - return DoubleNodeGen.create(); - } - - @Override - public Object getAsObject(RAbstractVector vector, Object store, int index) { - return get((RAbstractDoubleVector) vector, store, index); - } - - public final double get(RAbstractDoubleVector vector, Object store, int index) { - return execute(vector, store, index); - } - - public abstract double execute(RAbstractDoubleVector vector, Object store, int index); - - @Specialization(guards = "isNativeMirror(store)") - protected double doRVector(RDoubleVector vector, Object store, int index) { - return NativeDataAccess.getDoubleNativeMirrorData(store, index); - } - - @Specialization - protected double doRVector(RDoubleVector vector, double[] store, int index) { - return store[index]; - } - - @Specialization - protected double doSequence(RDoubleSequence sequence, Object store, int index) { - return sequence.getStart() + index * sequence.getStride(); - } - - @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3") - protected double doGenericCached(RAbstractDoubleVector vector, Object store, int index, - @Cached("vector.getClass()") Class<?> cachedClass) { - return ((RAbstractDoubleVector) cachedClass.cast(vector)).getDataAt(store, index); - } - - @Specialization(guards = "isGenericVector(vector)", replaces = "doGenericCached") - protected double doGeneric(RAbstractDoubleVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - @Fallback - protected double doFallback(RAbstractDoubleVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - protected static boolean isGenericVector(RAbstractDoubleVector vector) { - return !(vector instanceof RDoubleVector) && !(vector instanceof RDoubleSequence); - } - } - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Logical extends GetDataAt { - - public static Logical create() { - return GetDataAtFactory.LogicalNodeGen.create(); - } - - @Override - public Object getAsObject(RAbstractVector vector, Object store, int index) { - return get((RAbstractLogicalVector) vector, store, index); - } - - public final byte get(RAbstractLogicalVector vector, Object store, int index) { - return execute(vector, store, index); - } - - public abstract byte execute(RAbstractLogicalVector vector, Object store, int index); - - protected byte doRVector(RLogicalVector vector, byte[] store, int index) { - return store[index]; - } - - @Specialization(guards = "isNativeMirror(store)") - protected byte doRVector(RLogicalVector vector, Object store, int index) { - return NativeDataAccess.getLogicalNativeMirrorData(store, index); - } - - // This accounts for other vector types, like closures - @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3") - protected byte doGenericCached(RAbstractLogicalVector vector, Object store, int index, - @Cached("vector.getClass()") Class<? extends RAbstractLogicalVector> cachedClass) { - return cachedClass.cast(vector).getDataAt(store, index); - } - - @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached") - protected byte doGeneric(RAbstractLogicalVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - @Fallback - protected byte doFallback(RAbstractLogicalVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - protected static boolean isGenericVector(RAbstractLogicalVector vector) { - return !(vector instanceof RLogicalVector); - } - } - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Raw extends GetDataAt { - - public static Raw create() { - return GetDataAtFactory.RawNodeGen.create(); - } - - @Override - public Object getAsObject(RAbstractVector vector, Object store, int index) { - return get((RAbstractRawVector) vector, store, index); - } - - public final byte get(RAbstractRawVector vector, Object store, int index) { - return execute(vector, store, index); - } - - public abstract byte execute(RAbstractRawVector vector, Object store, int index); - - protected byte doRVector(RRawVector vector, byte[] store, int index) { - return store[index]; - } - - @Specialization(guards = "isNativeMirror(store)") - protected byte doRVector(RRawVector vector, Object store, int index) { - return NativeDataAccess.getRawNativeMirrorData(store, index); - } - - // This accounts for other vector types, like closures - @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3") - protected byte doGenericCached(RAbstractRawVector vector, Object store, int index, - @Cached("vector.getClass()") Class<? extends RAbstractRawVector> cachedClass) { - return cachedClass.cast(vector).getRawDataAt(store, index); - } - - @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached") - protected byte doGeneric(RAbstractRawVector vector, Object store, int index) { - return vector.getRawDataAt(store, index); - } - - @Fallback - protected byte doFallback(RAbstractRawVector vector, Object store, int index) { - return vector.getRawDataAt(store, index); - } - - protected static boolean isGenericVector(RAbstractRawVector vector) { - return !(vector instanceof RRawVector); - } - } - - @ImportStatic(NativeDataAccess.class) - public abstract static class Complex extends GetDataAt { - - public static Complex create() { - return GetDataAtFactory.ComplexNodeGen.create(); - } - - @Override - public Object getAsObject(RAbstractVector vector, Object store, int index) { - return get((RAbstractComplexVector) vector, store, index); - } - - public final RComplex get(RAbstractComplexVector vector, Object store, int index) { - return execute(vector, store, index); - } - - public abstract RComplex execute(RAbstractComplexVector vector, Object store, int index); - - protected RComplex doRVector(@SuppressWarnings("unused") RComplexVector vector, double[] store, int index) { - return RComplex.valueOf(store[index * 2], store[index * 2 + 1]); - } - - @SuppressWarnings("unused") - @Specialization(guards = "isNativeMirror(store)") - protected RComplex doRVector(RComplexVector vector, Object store, int index) { - throw RInternalError.unimplemented(); - } - - @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}, limit = "3") - protected RComplex doGenericCached(RAbstractComplexVector vector, Object store, int index, - @Cached("vector.getClass()") Class<? extends RAbstractComplexVector> cachedClass) { - return cachedClass.cast(vector).getDataAt(store, index); - } - - @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached") - protected RComplex doGeneric(RAbstractComplexVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - @Fallback - protected RComplex doFallback(RAbstractComplexVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - protected static boolean isGenericVector(RAbstractComplexVector vector) { - return !(vector instanceof RComplexVector); - } - } - - @ImportStatic(NativeDataAccess.class) - public abstract static class String extends GetDataAt { - - public static String create() { - return GetDataAtFactory.StringNodeGen.create(); - } - - @Override - public Object getAsObject(RAbstractVector vector, Object store, int index) { - return get((RAbstractStringVector) vector, store, index); - } - - public final java.lang.String get(RAbstractStringVector vector, Object store, int index) { - return execute(vector, store, index); - } - - public abstract java.lang.String execute(RAbstractStringVector vector, Object store, int index); - - protected java.lang.String doRVector(@SuppressWarnings("unused") RStringVector vector, java.lang.String[] store, int index) { - return store[index]; - } - - @SuppressWarnings("unused") - @Specialization(guards = "isNativeMirror(store)") - protected java.lang.String doRVector(RStringVector vector, Object store, int index) { - throw RInternalError.unimplemented(); - } - - @Specialization(guards = {"isGenericVector(vector)", "cachedClass == vector.getClass()"}) - protected java.lang.String doGenericCached(RAbstractStringVector vector, Object store, int index, - @Cached("vector.getClass()") Class<? extends RAbstractStringVector> cachedClass) { - return cachedClass.cast(vector).getDataAt(store, index); - } - - @Specialization(guards = {"isGenericVector(vector)"}, replaces = "doGenericCached") - protected java.lang.String doGeneric(RAbstractStringVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - @Fallback - protected java.lang.String doFallback(RAbstractStringVector vector, Object store, int index) { - return vector.getDataAt(store, index); - } - - protected static boolean isGenericVector(RAbstractStringVector vector) { - return !(vector instanceof RStringVector); - } - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataCopy.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataCopy.java deleted file mode 100644 index ebd66da59d1822a94aeefb09136854dd9f081673..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataCopy.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import java.util.Arrays; - -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.data.NativeDataAccess; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; -import com.oracle.truffle.r.runtime.data.nodes.GetDataCopyFactory.DoubleNodeGen; -import com.oracle.truffle.r.runtime.data.nodes.GetDataCopyFactory.StringNodeGen; - -/** - * Nodes contained in this class materialize given vector into an array of corresponding type. The - * array is always a copy of the original data and can be modified freely. - * - * @see RVector#getDataCopy() - */ -public abstract class GetDataCopy { - - public abstract static class Double extends Node { - public abstract double[] execute(RAbstractDoubleVector vector); - - public static Double create() { - return DoubleNodeGen.create(); - } - - @Specialization(guards = "!vec.hasNativeMemoryData()") - protected double[] doManagedRVector(RDoubleVector vec) { - double[] data = vec.getInternalManagedData(); - return Arrays.copyOf(data, data.length); - } - - @Specialization(guards = "vec.hasNativeMemoryData()") - protected double[] doNativeDataRVector(RDoubleVector vec) { - return NativeDataAccess.copyDoubleNativeData(vec.getNativeMirror()); - } - - @Fallback - protected double[] doOthers(RAbstractDoubleVector vec) { - int len = vec.getLength(); - double[] result = new double[len]; - Object store = vec.getInternalStore(); - for (int i = 0; i < len; i++) { - result[i] = vec.getDataAt(store, i); - } - return result; - } - } - - public abstract static class String extends Node { - public abstract java.lang.String[] execute(RAbstractStringVector vector); - - public static String create() { - return StringNodeGen.create(); - } - - @Specialization(guards = "vec.hasNativeMemoryData()") - protected java.lang.String[] doManagedRVector(@SuppressWarnings("unused") RStringVector vec) { - throw RInternalError.unimplemented("string vectors backed by native memory"); - } - - @Specialization(guards = "!vec.hasNativeMemoryData()") - protected java.lang.String[] doNativeDataRVector(RStringVector vec) { - java.lang.String[] data = vec.getInternalManagedData(); - return Arrays.copyOf(data, data.length); - } - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataStore.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataStore.java deleted file mode 100644 index a9baa4b4177c2b71b86db8754ceb76113a8e924f..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/GetDataStore.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.runtime.data.RVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; - -public abstract class GetDataStore extends Node { - - protected static final int CACHE_LIMIT = 6; - - public static GetDataStore create() { - return GetDataStoreNodeGen.create(); - } - - public abstract Object execute(RAbstractVector vector); - - @Specialization(guards = "vector.hasNativeMemoryData()") - protected Object doNative(RVector<?> vector) { - return vector.getNativeMirror(); - } - - @Specialization(guards = {"noNativeMemoryData(vector)", "vector.getClass() == vectorClass"}, limit = "CACHE_LIMIT") - protected Object doCached(RAbstractVector vector, - @Cached("vector.getClass()") Class<? extends RAbstractVector> vectorClass, - @Cached("getStoreClass(vector)") Class<?> storeClass) { - Object store = vectorClass.cast(vector).getInternalStore(); - assert store.getClass() == storeClass : "every concrete implementation of RAbstractVector#getInternalStore() must always return a store object of the same type."; - return storeClass.cast(store); - } - - @Specialization(replaces = "doCached", guards = {"noNativeMemoryData(vector)"}) - protected Object doGeneric(RAbstractVector vector) { - Object store = vector.getInternalStore(); - return store; - } - - @Fallback - protected Object doFallback(RAbstractVector vector) { - if (noNativeMemoryData(vector)) { - RVector<?> vec = (RVector<?>) vector; - if (vec.hasNativeMemoryData()) { - return vec.getNativeMirror(); - } - } - return vector.getInternalStore(); - } - - protected static boolean noNativeMemoryData(RAbstractVector vector) { - return !(vector instanceof RVector<?>) || !((RVector<?>) vector).hasNativeMemoryData(); - } - - protected static Class<?> getStoreClass(RAbstractVector vector) { - return vector.getInternalStore().getClass(); - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/PrimitiveVectorAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/PrimitiveVectorAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..9e92d4037552dfaa038d4534f47e474f56d3f10b --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/PrimitiveVectorAccess.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data.nodes; + +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromLogicalAccess; +import com.oracle.truffle.r.runtime.data.nodes.FastPathVectorAccess.FastPathFromStringAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromDoubleAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromIntAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromListAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromLogicalAccess; +import com.oracle.truffle.r.runtime.data.nodes.SlowPathVectorAccess.SlowPathFromStringAccess; + +public abstract class PrimitiveVectorAccess { + + public static VectorAccess create(Object value) { + if (value instanceof Integer) { + return new FastPathFromIntAccess(value) { + @Override + protected int getInt(Object store, int index) { + return (Integer) store; + } + }; + } else if (value instanceof Double) { + return new FastPathFromDoubleAccess(value) { + @Override + protected double getDouble(Object store, int index) { + return (Double) store; + } + }; + } else if (value instanceof Byte) { + return new FastPathFromLogicalAccess(value) { + @Override + protected byte getLogical(Object store, int index) { + return (Byte) store; + } + }; + } else if (value instanceof String) { + return new FastPathFromStringAccess(value) { + @Override + protected String getString(Object store, int index) { + return (String) store; + } + }; + } else if (value instanceof RNull) { + return new FastPathFromListAccess(value) { + @Override + public RType getType() { + return RType.Null; + } + + @Override + protected int getLength(Object vector) { + return 0; + } + + @Override + protected Object getListElement(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + }; + } else { + return null; + } + } + + private static final SlowPathFromIntAccess SLOW_PATH_INT = new SlowPathFromIntAccess() { + @Override + protected int getInt(Object store, int index) { + return (Integer) store; + } + }; + private static final SlowPathFromDoubleAccess SLOW_PATH_DOUBLE = new SlowPathFromDoubleAccess() { + @Override + protected double getDouble(Object store, int index) { + return (Double) store; + } + }; + private static final SlowPathFromLogicalAccess SLOW_PATH_LOGICAL = new SlowPathFromLogicalAccess() { + @Override + protected byte getLogical(Object store, int index) { + return (Byte) store; + } + }; + private static final SlowPathFromStringAccess SLOW_PATH_STRING = new SlowPathFromStringAccess() { + @Override + protected String getString(Object store, int index) { + return (String) store; + } + }; + private static final SlowPathFromListAccess SLOW_PATH_NULL = new SlowPathFromListAccess() { + @Override + public RType getType() { + return RType.Null; + } + + @Override + protected int getLength(Object vector) { + return 0; + } + + @Override + protected Object getListElement(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + }; + + public static VectorAccess createSlowPath(Object value) { + if (value instanceof Integer) { + return SLOW_PATH_INT; + } else if (value instanceof Double) { + return SLOW_PATH_DOUBLE; + } else if (value instanceof Byte) { + return SLOW_PATH_LOGICAL; + } else if (value instanceof String) { + return SLOW_PATH_STRING; + } else if (value instanceof RNull) { + return SLOW_PATH_NULL; + } else { + return null; + } + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/ReadAccessor.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/ReadAccessor.java deleted file mode 100644 index 997488a9dec3fc7235a0c4f3da6e1e13c101fa1a..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/ReadAccessor.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.r.runtime.data.RComplex; -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; - -/** - * Convenience classes that wraps {@link VectorReadAccess} node, the vector and its store so that - * those data can be passed around as a single paramter. - */ -public abstract class ReadAccessor { - private ReadAccessor() { - } - - public static final class Int extends ReadAccessor { - private final RAbstractIntVector vector; - private final VectorReadAccess.Int readAccess; - private final Object store; - - public Int(RAbstractIntVector vector, VectorReadAccess.Int readAccess) { - this.vector = vector; - this.readAccess = readAccess; - store = readAccess.getDataStore(vector); - } - - public int getDataAt(int index) { - return readAccess.getDataAt(vector, store, index); - } - - public Object getStore() { - return store; - } - - public RAbstractIntVector getVector() { - return vector; - } - } - - public static final class Double extends ReadAccessor { - private final RAbstractDoubleVector vector; - private final VectorReadAccess.Double readAccess; - private final Object store; - - public Double(RAbstractDoubleVector vector, VectorReadAccess.Double readAccess) { - this.vector = vector; - this.readAccess = readAccess; - store = readAccess.getDataStore(vector); - } - - public double getDataAt(int index) { - return readAccess.getDataAt(vector, store, index); - } - - public Object getStore() { - return store; - } - - public RAbstractDoubleVector getVector() { - return vector; - } - } - - public static final class Logical extends ReadAccessor { - private final RAbstractLogicalVector vector; - private final VectorReadAccess.Logical readAccess; - private final Object store; - - public Logical(RAbstractLogicalVector vector, VectorReadAccess.Logical readAccess) { - this.vector = vector; - this.readAccess = readAccess; - store = readAccess.getDataStore(vector); - } - - public byte getDataAt(int index) { - return readAccess.getDataAt(vector, store, index); - } - - public Object getStore() { - return store; - } - - public RAbstractLogicalVector getVector() { - return vector; - } - } - - public static final class Raw extends ReadAccessor { - private final RAbstractRawVector vector; - private final VectorReadAccess.Raw readAccess; - private final Object store; - - public Raw(RAbstractRawVector vector, VectorReadAccess.Raw readAccess) { - this.vector = vector; - this.readAccess = readAccess; - store = readAccess.getDataStore(vector); - } - - public byte getDataAt(int index) { - return readAccess.getDataAt(vector, store, index); - } - - public Object getStore() { - return store; - } - - public RAbstractRawVector getVector() { - return vector; - } - } - - public static final class Complex extends ReadAccessor { - private final RAbstractComplexVector vector; - private final VectorReadAccess.Complex readAccess; - private final Object store; - - public Complex(RAbstractComplexVector vector, VectorReadAccess.Complex readAccess) { - this.vector = vector; - this.readAccess = readAccess; - store = readAccess.getDataStore(vector); - } - - public RComplex getDataAt(int index) { - return readAccess.getDataAt(vector, store, index); - } - - public Object getStore() { - return store; - } - - public RAbstractComplexVector getVector() { - return vector; - } - } - - public static final class String extends ReadAccessor { - private final RAbstractStringVector vector; - private final VectorReadAccess.String readAccess; - private final Object store; - - public String(RAbstractStringVector vector, VectorReadAccess.String readAccess) { - this.vector = vector; - this.readAccess = readAccess; - store = readAccess.getDataStore(vector); - } - - public java.lang.String getDataAt(int index) { - return readAccess.getDataAt(vector, store, index); - } - - public Object getStore() { - return store; - } - - public RAbstractStringVector getVector() { - return vector; - } - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SetDataAt.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SetDataAt.java deleted file mode 100644 index 297b29b932ac9b31d16537c4dc78d3c7f2a9d1d8..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SetDataAt.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.data.NativeDataAccess; -import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RVector; - -public abstract class SetDataAt extends Node { - - public abstract void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value); - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Double extends SetDataAt { - - @Override - public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) { - setDataAt((RDoubleVector) vector, store, index, (double) value); - } - - public final void setDataAt(RDoubleVector vector, Object store, int index, double value) { - execute(vector, store, index, value); - } - - public abstract void execute(RDoubleVector vector, Object store, int index, double value); - - @Specialization(guards = "!isNativeMirror(store)") - protected void doManagedRVector(RDoubleVector vec, Object store, int index, double value) { - ((double[]) store)[index] = value; - } - - @Specialization(guards = "isNativeMirror(store)") - protected void doNativeDataRVector(RDoubleVector vec, Object store, int index, double value) { - NativeDataAccess.setNativeMirrorData(store, index, value); - } - - public static Double create() { - return SetDataAtFactory.DoubleNodeGen.create(); - } - } - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Int extends SetDataAt { - - @Override - public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) { - setDataAt((RIntVector) vector, store, index, (int) value); - } - - public final void setDataAt(RIntVector vector, Object store, int index, int value) { - execute(vector, store, index, value); - } - - public abstract void execute(RIntVector vector, Object store, int index, int value); - - @Specialization(guards = "!isNativeMirror(store)") - protected void doManagedRVector(RIntVector vec, Object store, int index, int value) { - ((int[]) store)[index] = value; - } - - @Specialization(guards = "isNativeMirror(store)") - protected void doNativeDataRVector(RIntVector vec, Object store, int index, int value) { - NativeDataAccess.setNativeMirrorData(store, index, value); - } - - public static Int create() { - return SetDataAtFactory.IntNodeGen.create(); - } - } - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Logical extends SetDataAt { - - @Override - public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) { - setDataAt((RLogicalVector) vector, store, index, (byte) value); - } - - public final void setDataAt(RLogicalVector vector, Object store, int index, byte value) { - execute(vector, store, index, value); - } - - public abstract void execute(RLogicalVector vector, Object store, int index, byte value); - - @Specialization(guards = "!isNativeMirror(store)") - protected void doManagedRVector(RLogicalVector vec, Object store, int index, byte value) { - ((byte[]) store)[index] = value; - } - - @Specialization(guards = "isNativeMirror(store)") - protected void doNativeDataRVector(RLogicalVector vec, Object store, int index, byte value) { - NativeDataAccess.setNativeMirrorData(store, index, value); - } - - public static Logical create() { - return SetDataAtFactory.LogicalNodeGen.create(); - } - } - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Raw extends SetDataAt { - - @Override - public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) { - setDataAt((RRawVector) vector, store, index, (byte) value); - } - - public final void setDataAt(RRawVector vector, Object store, int index, byte value) { - execute(vector, store, index, value); - } - - public abstract void execute(RRawVector vector, Object store, int index, byte value); - - @Specialization(guards = "!isNativeMirror(store)") - protected void doManagedRVector(RRawVector vec, Object store, int index, byte value) { - ((byte[]) store)[index] = value; - } - - @Specialization(guards = "isNativeMirror(store)") - protected void doNativeDataRVector(RRawVector vec, Object store, int index, byte value) { - NativeDataAccess.setNativeMirrorData(store, index, value); - } - - public static Raw create() { - return SetDataAtFactory.RawNodeGen.create(); - } - } - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class Complex extends SetDataAt { - - @Override - public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) { - setDataAt((RComplexVector) vector, store, index, (RComplex) value); - } - - public final void setDataAt(RComplexVector vector, Object store, int index, RComplex value) { - execute(vector, store, index, value); - } - - public abstract void execute(RComplexVector vector, Object store, int index, RComplex value); - - @Specialization(guards = "!isNativeMirror(storeObj)") - protected void doManagedRVector(RComplexVector vec, Object storeObj, int index, RComplex value) { - double[] store = (double[]) storeObj; - store[index * 2] = value.getRealPart(); - store[index * 2 + 1] = value.getImaginaryPart(); - } - - @Specialization(guards = "isNativeMirror(store)") - protected void doNativeDataRVector(RComplexVector vec, Object store, int index, RComplex value) { - throw RInternalError.unimplemented(); - } - - public static Complex create() { - return SetDataAtFactory.ComplexNodeGen.create(); - } - } - - @ImportStatic(NativeDataAccess.class) - @SuppressWarnings("unused") - public abstract static class String extends SetDataAt { - - @Override - public final void setDataAtAsObject(RVector<?> vector, Object store, int index, Object value) { - setDataAt((RStringVector) vector, store, index, (java.lang.String) value); - } - - public final void setDataAt(RStringVector vector, Object store, int index, java.lang.String value) { - execute(vector, store, index, value); - } - - public abstract void execute(RStringVector vector, Object store, int index, java.lang.String value); - - @Specialization(guards = "!isNativeMirror(store)") - protected void doManagedRVector(RStringVector vec, Object store, int index, java.lang.String value) { - ((java.lang.String[]) store)[index] = value; - } - - @Specialization(guards = "isNativeMirror(store)") - protected void doNativeDataRVector(RStringVector vec, Object store, int index, java.lang.String value) { - throw RInternalError.unimplemented(); - } - - public static String create() { - return SetDataAtFactory.StringNodeGen.create(); - } - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SlowPathVectorAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SlowPathVectorAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..5aeab7e21738e334fe5fdf795fc6e12b7ad5f227 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/SlowPathVectorAccess.java @@ -0,0 +1,606 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data.nodes; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RError.Message; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.RType; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RComplex; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; + +/** + * Base classes for {@link VectorAccess} implementations that are used on the slow path, i.e., that + * are created as singletons. For implementation reasons, most of this code is mirrored in + * {@link FastPathVectorAccess}, so that any changes need to be mirrored there. + */ +public abstract class SlowPathVectorAccess extends VectorAccess { + + protected boolean naReported; // TODO: move this into the iterator + + protected SlowPathVectorAccess() { + // VectorAccess.supports has an assertion that relies on this being Object.class + super(Object.class, true); + } + + @Override + protected final Object getStore(RAbstractContainer vector) { + return vector; + } + + protected final void warning(RError.Message message) { + CompilerAsserts.neverPartOfCompilation(); + if (!naReported) { + RError.warning(RError.SHOW_CALLER, message); + naReported = true; + } + } + + public abstract static class SlowPathFromIntAccess extends SlowPathVectorAccess { + + @Override + public final RType getType() { + return RType.Integer; + } + + @Override + protected final double getDouble(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.DOUBLE_NA : RRuntime.int2doubleNoCheck(value); + } + + @Override + protected final byte getRaw(Object store, int index) { + int value = getInt(store, index); + byte result = (byte) value; + if ((result & 0xff) != value) { + warning(Message.OUT_OF_RANGE); + return 0; + } + return result; + } + + @Override + protected final byte getLogical(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.int2logicalNoCheck(value); + } + + @Override + protected final RComplex getComplex(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RComplex.createNA() : RRuntime.int2complexNoCheck(value); + } + + @Override + protected final double getComplexR(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value; + } + + @Override + protected final double getComplexI(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0; + } + + @Override + protected final String getString(Object store, int index) { + int value = getInt(store, index); + return na.check(value) ? RRuntime.STRING_NA : RRuntime.intToStringNoCheck(value); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getInt(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setInt(store, index, sourceAccess.getInt(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setInt(store, index, sourceAccess.getInt(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setInt(store, index, RRuntime.INT_NA); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getInt(store, index)); + } + } + + public abstract static class SlowPathFromDoubleAccess extends SlowPathVectorAccess { + + @Override + public final RType getType() { + return RType.Double; + } + + @Override + protected final int getInt(Object store, int index) { + double value = getDouble(store, index); + if (Double.isNaN(value)) { + na.enable(true); + return RRuntime.INT_NA; + } + if (value > Integer.MAX_VALUE || value <= Integer.MIN_VALUE) { + na.enable(true); + warning(Message.NA_INTRODUCED_COERCION_INT); + return RRuntime.INT_NA; + } + return (int) value; + } + + @Override + protected final byte getRaw(Object store, int index) { + int value = (int) getDouble(store, index); + byte result = (byte) value; + if ((result & 0xff) != value) { + warning(Message.OUT_OF_RANGE); + return 0; + } + return result; + } + + @Override + protected final byte getLogical(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.double2logicalNoCheck(value); + } + + @Override + protected final RComplex getComplex(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RComplex.createNA() : RRuntime.double2complexNoCheck(value); + } + + @Override + protected final double getComplexR(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value; + } + + @Override + protected final double getComplexI(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0; + } + + @Override + protected final String getString(Object store, int index) { + double value = getDouble(store, index); + return na.check(value) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeDouble(value); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getDouble(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setDouble(store, index, sourceAccess.getDouble(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setDouble(store, index, sourceAccess.getDouble(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setDouble(store, index, RRuntime.DOUBLE_NA); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getDouble(store, index)); + } + } + + public abstract static class SlowPathFromLogicalAccess extends SlowPathVectorAccess { + + @Override + public final RType getType() { + return RType.Logical; + } + + @Override + protected final int getInt(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.INT_NA : RRuntime.logical2intNoCheck(value); + } + + @Override + protected final double getDouble(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.DOUBLE_NA : RRuntime.logical2doubleNoCheck(value); + } + + @Override + protected final byte getRaw(Object store, int index) { + byte value = getLogical(store, index); + if (na.check(value)) { + warning(Message.OUT_OF_RANGE); + return 0; + } + return value; + } + + @Override + protected final RComplex getComplex(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RComplex.createNA() : RRuntime.logical2complexNoCheck(value); + } + + @Override + protected final double getComplexR(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_REAL_PART : value; + } + + @Override + protected final double getComplexI(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.COMPLEX_NA_IMAGINARY_PART : 0; + } + + @Override + protected final String getString(Object store, int index) { + byte value = getLogical(store, index); + return na.check(value) ? RRuntime.STRING_NA : RRuntime.logicalToStringNoCheck(value); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getLogical(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setLogical(store, index, sourceAccess.getLogical(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setLogical(store, index, sourceAccess.getLogical(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setLogical(store, index, RRuntime.LOGICAL_NA); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getLogical(store, index)); + } + } + + public abstract static class SlowPathFromRawAccess extends SlowPathVectorAccess { + + @Override + public final RType getType() { + return RType.Raw; + } + + @Override + protected final int getInt(Object store, int index) { + return getRaw(store, index) & 0xff; + } + + @Override + protected final double getDouble(Object store, int index) { + return getRaw(store, index) & 0xff; + } + + @Override + protected final byte getLogical(Object store, int index) { + return getRaw(store, index) == 0 ? RRuntime.LOGICAL_FALSE : RRuntime.LOGICAL_TRUE; + } + + @Override + protected final RComplex getComplex(Object store, int index) { + return RComplex.valueOf(getRaw(store, index) & 0xff, 0); + } + + @Override + protected final double getComplexR(Object store, int index) { + return getRaw(store, index) & 0xff; + } + + @Override + protected final double getComplexI(Object store, int index) { + return 0; + } + + @Override + protected final String getString(Object store, int index) { + return RRuntime.rawToHexString(getRaw(store, index)); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getRaw(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setRaw(store, index, sourceAccess.getRaw(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setRaw(store, index, sourceAccess.getRaw(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + /* + * There is no raw NA, but places that write NA for other types usually write 0 for raw. + */ + setRaw(store, index, (byte) 0); + } + + @Override + protected boolean isNA(Object store, int index) { + return false; + } + } + + public abstract static class SlowPathFromComplexAccess extends SlowPathVectorAccess { + + @Override + public final RType getType() { + return RType.Complex; + } + + @Override + protected final int getInt(Object store, int index) { + double value = getComplexR(store, index); + if (Double.isNaN(value)) { + na.enable(true); + return RRuntime.INT_NA; + } + if (value > Integer.MAX_VALUE || value <= Integer.MIN_VALUE) { + na.enable(true); + warning(Message.NA_INTRODUCED_COERCION_INT); + return RRuntime.INT_NA; + } + if (getComplexI(store, index) != 0) { + warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION); + } + return (int) value; + } + + @Override + protected final double getDouble(Object store, int index) { + double value = getComplexR(store, index); + if (Double.isNaN(value)) { + na.enable(true); + return RRuntime.DOUBLE_NA; + } + if (getComplexI(store, index) != 0) { + warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION); + } + return value; + } + + @Override + protected final byte getRaw(Object store, int index) { + double value = getComplexR(store, index); + if (Double.isNaN(value) || value < 0 || value >= 256) { + warning(Message.OUT_OF_RANGE); + return 0; + } + if (getComplexI(store, index) != 0) { + warning(Message.IMAGINARY_PARTS_DISCARDED_IN_COERCION); + } + return (byte) value; + } + + @Override + protected final byte getLogical(Object store, int index) { + RComplex value = getComplex(store, index); + return na.check(value) ? RRuntime.LOGICAL_NA : RRuntime.complex2logicalNoCheck(value); + } + + @Override + protected final String getString(Object store, int index) { + RComplex value = getComplex(store, index); + return na.check(value) ? RRuntime.STRING_NA : RContext.getRRuntimeASTAccess().encodeComplex(value); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getComplex(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setComplex(store, index, sourceAccess.getComplexR(sourceIter), sourceAccess.getComplexI(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setComplex(store, index, sourceAccess.getComplexR(sourceIter, sourceIndex), sourceAccess.getComplexI(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setComplex(store, index, RRuntime.COMPLEX_NA_REAL_PART, RRuntime.COMPLEX_NA_IMAGINARY_PART); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getComplexR(store, index), getComplexI(store, index)); + } + } + + public abstract static class SlowPathFromStringAccess extends SlowPathVectorAccess { + + @Override + public final RType getType() { + return RType.Character; + } + + @Override + protected final int getInt(Object store, int index) { + return na.convertStringToInt(getString(store, index)); + } + + @Override + protected final double getDouble(Object store, int index) { + return na.convertStringToDouble(getString(store, index)); + } + + @Override + protected final byte getRaw(Object store, int index) { + int value = na.convertStringToInt(getString(store, index)); + return value >= 0 && value <= 255 ? (byte) value : 0; + } + + @Override + protected final byte getLogical(Object store, int index) { + return na.convertStringToLogical(getString(store, index)); + } + + @Override + protected final RComplex getComplex(Object store, int index) { + return na.convertStringToComplex(getString(store, index)); + } + + @Override + protected final double getComplexR(Object store, int index) { + return na.convertStringToComplex(getString(store, index)).getRealPart(); + } + + @Override + protected final double getComplexI(Object store, int index) { + return na.convertStringToComplex(getString(store, index)).getImaginaryPart(); + } + + @Override + protected final Object getListElement(Object store, int index) { + return getString(store, index); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setString(store, index, sourceAccess.getString(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setString(store, index, sourceAccess.getString(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + setString(store, index, RRuntime.STRING_NA); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.check(getString(store, index)); + } + } + + public abstract static class SlowPathFromListAccess extends SlowPathVectorAccess { + + @Override + protected final int getInt(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final double getDouble(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final byte getRaw(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final byte getLogical(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final RComplex getComplex(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final double getComplexR(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final double getComplexI(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final String getString(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setListElement(store, index, sourceAccess.getListElement(sourceIter)); + } + + @Override + protected final void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setListElement(store, index, sourceAccess.getListElement(sourceIter, sourceIndex)); + } + + @Override + protected void setNA(Object store, int index) { + /* + * There is no list NA, but places that write NA for other types usually write NULL for + * lists. + */ + setListElement(store, index, RNull.instance); + } + + @Override + protected boolean isNA(Object store, int index) { + return na.checkListElement(getListElement(store, index)); + } + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..e64b83486777349043f84c6bcc75cc60c2470f8b --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccess.java @@ -0,0 +1,547 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data.nodes; + +import com.oracle.truffle.api.CompilerAsserts; +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.api.nodes.Node; +import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RType; +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; +import com.oracle.truffle.r.runtime.data.RExpression; +import com.oracle.truffle.r.runtime.data.RIntVector; +import com.oracle.truffle.r.runtime.data.RList; +import com.oracle.truffle.r.runtime.data.RLogicalVector; +import com.oracle.truffle.r.runtime.data.RRawVector; +import com.oracle.truffle.r.runtime.data.RStringVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; +import com.oracle.truffle.r.runtime.nodes.RBaseNode; +import com.oracle.truffle.r.runtime.ops.na.NACheck; + +/** + * This class is the main access point for reading and writing vectors. Every implementation of + * {@link RAbstractContainer} needs to be able to supply an instance of {@link VectorAccess} via the + * {@link RAbstractContainer#access()} function. These instances can be asked, via the + * {@link #supports(Object)} function, whether they support a specific object.<br/> + * + * The usual interaction with vectors looks like this: + * <ul> + * <li>{@link Specialization} {@code foo} has a vector as a parameter, and adds a {@link Cached} + * parameter of type {@link VectorAccess} that is initialized by {@link RAbstractContainer#access()} + * .</li> + * <li>The specialization guards with {@code access.supports(vector)} so that it only handles cases + * that it actually supports.</li> + * <li>try-with-resources is used to open an access (either sequential or random) on the vector: + * <br/> + * {@code try (SequentialIterator iter = access.access(vector))...}</li> + * <li>Inside the try-with-resources, individual elements can be accessed using the + * {@link VectorAccess#getInt(SequentialIterator)}, etc. functions</li> + * <li>A fallback specialization, which {@link Specialization#replaces()} the original one and + * creates the {@link VectorAccess} via {@link RAbstractContainer#slowPathAccess()}, calls the first + * specialization with the slow path vector access.</li> + * </ul> + */ +public abstract class VectorAccess extends Node { + + public final NACheck na = NACheck.create(); + + protected final Class<?> clazz; + protected final boolean hasStore; + + public VectorAccess(Class<?> clazz, boolean hasStore) { + CompilerAsserts.neverPartOfCompilation(); + this.clazz = clazz; + this.hasStore = hasStore; + } + + public static final class SequentialIterator implements AutoCloseable { + + protected final Object store; // internal store, native mirror or vector + protected final int length; + protected int index; + + private SequentialIterator(Object store, int length) { + this.store = store; + this.length = length; + this.index = -1; + } + + @Override + public void close() { + // nothing to do + } + + public int getIndex() { + return index; + } + + Object getStore() { + return store; + } + + @Override + public String toString() { + return String.format("<iterator %d of %d, %s>", index, length, store == null ? "null" : store.getClass().getSimpleName()); + } + } + + public static final class RandomIterator implements AutoCloseable { + + protected final Object store; // internal store, native mirror or vector + protected final int length; + + private RandomIterator(Object store, int length) { + this.store = store; + this.length = length; + } + + @Override + public void close() { + // nothing to do + } + + Object getStore() { + return store; + } + + @Override + public String toString() { + return String.format("<random access %s>", store == null ? "null" : store.getClass().getSimpleName()); + } + } + + protected abstract int getInt(Object store, int index); + + protected abstract double getDouble(Object store, int index); + + protected abstract RComplex getComplex(Object store, int index); + + protected abstract double getComplexR(Object store, int index); + + protected abstract double getComplexI(Object store, int index); + + protected abstract byte getRaw(Object store, int index); + + protected abstract byte getLogical(Object store, int index); + + protected abstract String getString(Object store, int index); + + protected abstract Object getListElement(Object store, int index); + + @SuppressWarnings("unused") + protected void setInt(Object store, int index, int value) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setDouble(Object store, int index, double value) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setComplex(Object store, int index, double real, double imaginary) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setRaw(Object store, int index, byte value) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setLogical(Object store, int index, byte value) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setString(Object store, int index, String value) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setListElement(Object store, int index, Object value) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setFromSameType(Object store, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setFromSameType(Object store, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + throw RInternalError.shouldNotReachHere(); + } + + @SuppressWarnings("unused") + protected void setNA(Object store, int index) { + throw RInternalError.shouldNotReachHere(); + } + + protected abstract boolean isNA(Object store, int index); + + public final Object cast(Object value) { + return clazz.cast(value); + } + + public final boolean supports(Object value) { + assert clazz != Object.class : "cannot call 'supports' on slow path vector access"; + if (value.getClass() != clazz) { + return false; + } + Object castVector = cast(value); + return !(castVector instanceof RAbstractContainer) || (((RAbstractContainer) castVector).getInternalStore() != null) == hasStore; + } + + protected abstract Object getStore(RAbstractContainer vector); + + protected int getLength(RAbstractContainer vector) { + return vector.getLength(); + } + + protected int getLength(@SuppressWarnings("unused") Object vector) { + return 1; + } + + /** + * Creates a new iterator that will point to before the beginning of the vector, so that + * {@link #next(SequentialIterator)} will move it to the first element. + */ + public final SequentialIterator access(Object vector) { + Object castVector = cast(vector); + if (castVector instanceof RAbstractContainer) { + RAbstractContainer container = (RAbstractContainer) castVector; + int length = getLength(container); + RBaseNode.reportWork(this, length); + na.enable(container); + return new SequentialIterator(getStore(container), length); + } else { + na.enable(true); + return new SequentialIterator(castVector, getLength(castVector)); + } + } + + @SuppressWarnings("static-method") + public final boolean next(SequentialIterator iter) { + return ++iter.index < iter.length; + } + + @SuppressWarnings("static-method") + public final void nextWithWrap(SequentialIterator iter) { + assert iter.length > 0; + if (++iter.index >= iter.length) { + iter.index = 0; + } + } + + @SuppressWarnings("static-method") + public final int getLength(SequentialIterator iter) { + return iter.length; + } + + /** + * Resets the iterator to point to before the first element, calling + * {@link #next(SequentialIterator)} will move it to the first element. + */ + @SuppressWarnings("static-method") + public final void reset(SequentialIterator iter) { + iter.index = -1; + } + + public abstract RType getType(); + + public final int getInt(SequentialIterator iter) { + return getInt(iter.store, iter.index); + } + + public final double getDouble(SequentialIterator iter) { + return getDouble(iter.store, iter.index); + } + + public final RComplex getComplex(SequentialIterator iter) { + return getComplex(iter.store, iter.index); + } + + public final double getComplexR(SequentialIterator iter) { + return getComplexR(iter.store, iter.index); + } + + public final double getComplexI(SequentialIterator iter) { + return getComplexI(iter.store, iter.index); + } + + public final byte getRaw(SequentialIterator iter) { + return getRaw(iter.store, iter.index); + } + + public final byte getLogical(SequentialIterator iter) { + return getLogical(iter.store, iter.index); + } + + public final String getString(SequentialIterator iter) { + return getString(iter.store, iter.index); + } + + public final Object getListElement(SequentialIterator iter) { + return getListElement(iter.store, iter.index); + } + + public final void setInt(SequentialIterator iter, int value) { + setInt(iter.store, iter.index, value); + } + + public final void setDouble(SequentialIterator iter, double value) { + setDouble(iter.store, iter.index, value); + } + + public final void setComplex(SequentialIterator iter, double real, double imaginary) { + setComplex(iter.store, iter.index, real, imaginary); + } + + public final void setRaw(SequentialIterator iter, byte value) { + setRaw(iter.store, iter.index, value); + } + + public final void setLogical(SequentialIterator iter, byte value) { + setLogical(iter.store, iter.index, value); + } + + public final void setString(SequentialIterator iter, String value) { + setString(iter.store, iter.index, value); + } + + public final void setListElement(SequentialIterator iter, Object value) { + setListElement(iter.store, iter.index, value); + } + + public final void setFromSameType(SequentialIterator iter, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setFromSameType(iter.store, iter.index, sourceAccess, sourceIter); + } + + public final void setFromSameType(SequentialIterator iter, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setFromSameType(iter.store, iter.index, sourceAccess, sourceIter, sourceIndex); + } + + public final void setNA(SequentialIterator iter) { + setNA(iter.store, iter.index); + } + + public final boolean isNA(SequentialIterator iter) { + return isNA(iter.store, iter.index); + } + + /** + * Creates a new random access on the given vector. + */ + public final RandomIterator randomAccess(RAbstractContainer vector) { + Object castVector = cast(vector); + if (castVector instanceof RAbstractContainer) { + RAbstractContainer container = (RAbstractContainer) castVector; + int length = getLength(container); + RBaseNode.reportWork(this, length); + na.enable(container); + return new RandomIterator(getStore(container), length); + } else { + na.enable(true); + return new RandomIterator(castVector, getLength(castVector)); + } + } + + @SuppressWarnings("static-method") + public final int getLength(RandomIterator iter) { + return iter.length; + } + + public final int getInt(RandomIterator iter, int index) { + return getInt(iter.store, index); + } + + public final double getDouble(RandomIterator iter, int index) { + return getDouble(iter.store, index); + } + + public final RComplex getComplex(RandomIterator iter, int index) { + return getComplex(iter.store, index); + } + + public final double getComplexR(RandomIterator iter, int index) { + return getComplexR(iter.store, index); + } + + public final double getComplexI(RandomIterator iter, int index) { + return getComplexI(iter.store, index); + } + + public final byte getRaw(RandomIterator iter, int index) { + return getRaw(iter.store, index); + } + + public final byte getLogical(RandomIterator iter, int index) { + return getLogical(iter.store, index); + } + + public final String getString(RandomIterator iter, int index) { + return getString(iter.store, index); + } + + public final Object getListElement(RandomIterator iter, int index) { + return getListElement(iter.store, index); + } + + public final void setInt(RandomIterator iter, int index, int value) { + setInt(iter.store, index, value); + } + + public final void setDouble(RandomIterator iter, int index, double value) { + setDouble(iter.store, index, value); + } + + public final void setComplex(RandomIterator iter, int index, double real, double imaginary) { + setComplex(iter.store, index, real, imaginary); + } + + public final void setRaw(RandomIterator iter, int index, byte value) { + setRaw(iter.store, index, value); + } + + public final void setLogical(RandomIterator iter, int index, byte value) { + setLogical(iter.store, index, value); + } + + public final void setString(RandomIterator iter, int index, String value) { + setString(iter.store, index, value); + } + + public final void setListElement(RandomIterator iter, int index, Object value) { + setListElement(iter.store, index, value); + } + + public final void setFromSameType(RandomIterator iter, int index, VectorAccess sourceAccess, SequentialIterator sourceIter) { + setFromSameType(iter.store, index, sourceAccess, sourceIter); + } + + public final void setFromSameType(RandomIterator iter, int index, VectorAccess sourceAccess, RandomIterator sourceIter, int sourceIndex) { + setFromSameType(iter.store, index, sourceAccess, sourceIter, sourceIndex); + } + + public final void setNA(RandomIterator iter, int index) { + setNA(iter.store, index); + } + + public final boolean isNA(RandomIterator iter, int index) { + return isNA(iter.store, index); + } + + /** + * Placed in a separate class to avoid circular dependencies during class initialization. + */ + private static final class Lazy { + private static final RStringVector TEMPLATE_CHARACTER = RDataFactory.getPermanent().createStringVector(4); + private static final RComplexVector TEMPLATE_COMPLEX = RDataFactory.getPermanent().createComplexVector(4); + private static final RDoubleVector TEMPLATE_DOUBLE = RDataFactory.getPermanent().createDoubleVector(4); + private static final RIntVector TEMPLATE_INTEGER = RDataFactory.getPermanent().createIntVector(4); + private static final RList TEMPLATE_LIST = RDataFactory.getPermanent().createList(4); + private static final RExpression TEMPLATE_EXPRESSION = RDataFactory.createExpression(4); + private static final RLogicalVector TEMPLATE_LOGICAL = RDataFactory.getPermanent().createLogicalVector(4); + private static final RRawVector TEMPLATE_RAW = RDataFactory.getPermanent().createRawVector(4); + } + + public static VectorAccess createNew(RType type) { + CompilerAsserts.neverPartOfCompilation(); + switch (type) { + case Character: + return Lazy.TEMPLATE_CHARACTER.access(); + case Complex: + return Lazy.TEMPLATE_COMPLEX.access(); + case Double: + return Lazy.TEMPLATE_DOUBLE.access(); + case Integer: + return Lazy.TEMPLATE_INTEGER.access(); + case List: + return Lazy.TEMPLATE_LIST.access(); + case Expression: + return Lazy.TEMPLATE_EXPRESSION.access(); + case Logical: + return Lazy.TEMPLATE_LOGICAL.access(); + case Raw: + return Lazy.TEMPLATE_RAW.access(); + case RInteropChar: + case RInteropFloat: + case RInteropLong: + case RInteropShort: + default: + throw RInternalError.shouldNotReachHere(); + } + } + + @TruffleBoundary + public static VectorAccess createSlowPathNew(RType type) { + switch (type) { + case Character: + return Lazy.TEMPLATE_CHARACTER.slowPathAccess(); + case Complex: + return Lazy.TEMPLATE_COMPLEX.slowPathAccess(); + case Double: + return Lazy.TEMPLATE_DOUBLE.slowPathAccess(); + case Integer: + return Lazy.TEMPLATE_INTEGER.slowPathAccess(); + case List: + return Lazy.TEMPLATE_LIST.slowPathAccess(); + case Expression: + return Lazy.TEMPLATE_EXPRESSION.slowPathAccess(); + case Logical: + return Lazy.TEMPLATE_LOGICAL.slowPathAccess(); + case Raw: + return Lazy.TEMPLATE_RAW.slowPathAccess(); + case RInteropChar: + case RInteropFloat: + case RInteropLong: + case RInteropShort: + default: + throw RInternalError.shouldNotReachHere(); + } + } + + public static VectorAccess create(Object value) { + CompilerAsserts.neverPartOfCompilation(); + if (value instanceof RAbstractContainer) { + return ((RAbstractContainer) value).access(); + } else { + return PrimitiveVectorAccess.create(value); + } + } + + @TruffleBoundary + public static VectorAccess createSlowPath(Object value) { + if (value instanceof RAbstractContainer) { + return ((RAbstractContainer) value).slowPathAccess(); + } else { + return PrimitiveVectorAccess.createSlowPath(value); + } + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccessAdapter.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccessAdapter.java deleted file mode 100644 index c42c45e40b347a26f98af44574d13f8be368f044..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorAccessAdapter.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; - -/** - * Factors out common code. - */ -abstract class VectorAccessAdapter extends Node { - @Child private GetDataStore getDataStoreNode = GetDataStoreNodeGen.create(); - - public Object getDataStore(RAbstractVector vector) { - return getDataStoreNode.execute(vector); - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java deleted file mode 100644 index ebb528ff5b3ccd8372e846f4a9f0f33f6b06e57a..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorIterator.java +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.ValueType; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Fallback; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.Utils; -import com.oracle.truffle.r.runtime.data.NativeDataAccess; -import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RVector; -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.GetNextNodeGen.GetNextGenericNodeGen; -import com.oracle.truffle.r.runtime.data.nodes.VectorIterator.IteratorData; - -abstract class VectorIteratorNodeAdapter extends Node { - public static boolean hasNoNativeMemoryData(RAbstractVector vector, Class<? extends RAbstractVector> vecClass) { - return !(RVector.class.isAssignableFrom(vecClass)) || !((RVector<?>) vecClass.cast(vector)).hasNativeMemoryData(); - } - - public static boolean isRVector(Class<? extends RAbstractVector> vecClass) { - return RVector.class.isAssignableFrom(vecClass); - } -} - -abstract class GetIteratorNode extends VectorIteratorNodeAdapter { - public abstract IteratorData<?> execute(RAbstractVector vector); - - @Specialization(guards = "vector.hasNativeMemoryData()") - protected IteratorData<?> nativeMirrorIterator(RVector<?> vector) { - return new IteratorData<>(vector.getNativeMirror(), vector.getLength()); - } - - @Specialization(guards = {"vectorClass == vector.getClass()", "hasNoNativeMemoryData(vector, vectorClass)"}, limit = "10") - protected IteratorData<?> cached(RAbstractVector vector, - @Cached("vector.getClass()") Class<? extends RAbstractVector> vectorClass) { - RAbstractVector profiledVec = vectorClass.cast(vector); - return new IteratorData<>(profiledVec.getInternalStore(), profiledVec.getLength()); - } - - @Specialization(replaces = "cached", guards = {"hasNoNativeMemoryData(vector, vector.getClass())"}) - protected IteratorData<?> generic(RAbstractVector vector) { - RAbstractVector profiledVec = vector; - return new IteratorData<>(profiledVec.getInternalStore(), profiledVec.getLength()); - } - - @Fallback - protected IteratorData<?> fallback(RAbstractVector vector) { - return new IteratorData<>(vector.getInternalStore(), vector.getLength()); - } -} - -@SuppressWarnings("unused") -abstract class HasNextNode extends VectorIteratorNodeAdapter { - public abstract boolean execute(RAbstractVector vector, IteratorData<?> iterator); - - @Specialization(guards = "!iter.hasNativeMirror()") - protected boolean intVector(RIntVector vector, IteratorData<?> iter) { - return iter.index < ((int[]) iter.store).length; - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected boolean doubleVector(RDoubleVector vector, IteratorData<?> iter) { - return iter.index < ((double[]) iter.store).length; - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected boolean logicalVector(RLogicalVector vector, IteratorData<?> iter) { - return iter.index < ((byte[]) iter.store).length; - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected boolean rawVector(RRawVector vector, IteratorData<?> iter) { - return iter.index < ((byte[]) iter.store).length; - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected boolean stringVector(RStringVector vector, IteratorData<?> iter) { - return iter.index < ((String[]) iter.store).length; - } - - @Specialization(guards = {"vectorClass == vector.getClass()", "!isRVector(vectorClass)"}, limit = "10") - protected boolean generic(RAbstractVector vector, IteratorData<?> iter, - @Cached("vector.getClass()") Class<? extends RAbstractVector> vectorClass) { - RAbstractVector profiledVec = vectorClass.cast(vector); - return iter.index < profiledVec.getLength(); - } - - @Specialization - protected boolean generic(RAbstractVector vector, IteratorData<?> iter) { - return iter.index < vector.getLength(); - } -} - -@SuppressWarnings("unused") -abstract class GetNextNode extends VectorIteratorNodeAdapter { - public abstract Object execute(RAbstractVector vector, IteratorData<?> iterator); - - @Specialization(guards = "!iter.hasNativeMirror()") - protected int intVector(RIntVector vector, IteratorData<?> iter) { - return ((int[]) iter.store)[iter.index]; - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected double doubleVector(RDoubleVector vector, IteratorData<?> iter) { - return ((double[]) iter.store)[iter.index]; - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected byte logicalVector(RLogicalVector vector, IteratorData<?> iter) { - return ((byte[]) iter.store)[iter.index]; - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected RComplex doComplexVector(RComplexVector vector, IteratorData<?> iter) { - double[] arr = (double[]) iter.store; - return RComplex.valueOf(arr[iter.index * 2], arr[iter.index * 2 + 1]); - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected byte doRawVector(RRawVector vector, IteratorData<?> iter) { - return ((byte[]) iter.store)[iter.index]; - } - - @Specialization(guards = "!iter.hasNativeMirror()") - protected String doStringVector(RStringVector vector, IteratorData<?> iter) { - return ((String[]) iter.store)[iter.index]; - } - - @Specialization(guards = "iter.hasNativeMirror()") - protected int intVectorNative(RIntVector vector, IteratorData<?> iter) { - return NativeDataAccess.getIntNativeMirrorData(iter.store, iter.index); - } - - @Specialization(guards = "iter.hasNativeMirror()") - protected double doubleVectorNative(RDoubleVector vector, IteratorData<?> iter) { - return NativeDataAccess.getDoubleNativeMirrorData(iter.store, iter.index); - } - - @Specialization(guards = "iter.hasNativeMirror()") - protected byte logicalVectorNative(RLogicalVector vector, IteratorData<?> iter) { - return NativeDataAccess.getLogicalNativeMirrorData(iter.store, iter.index); - } - - @Specialization(guards = "iter.hasNativeMirror()") - protected byte doubleVectorNative(RRawVector vector, IteratorData<?> iter) { - return NativeDataAccess.getRawNativeMirrorData(iter.store, iter.index); - } - - @Specialization(guards = "iter.hasNativeMirror()") - protected RComplex complexVectorNative(RComplexVector vector, IteratorData<?> iter) { - return NativeDataAccess.getComplexNativeMirrorData(iter.store, iter.index); - } - - @Specialization(guards = "iter.hasNativeMirror()") - protected byte stringVectorNative(RStringVector vector, IteratorData<?> iter) { - throw RInternalError.unimplemented("string vectors backed by native memory"); - } - - @Child private GetNextGenericNode getNextGenericNode; - - @Fallback - protected Object doGeneric(RAbstractVector vector, IteratorData<?> iter) { - // we use fallback and extra node so that we do not have to explicitly check that the vector - // is not - // RVector, DSL generates fallback guard that compares the class with the all RVector - // subclasses - // used in the specializations above, "vector instanceof RVector" would not be a leaf-check. - if (getNextGenericNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - getNextGenericNode = insert(GetNextGenericNode.create()); - } - return getNextGenericNode.execute(vector, iter); - } - - abstract static class GetNextGenericNode extends Node { - public abstract Object execute(RAbstractVector vector, IteratorData<?> iter); - - public static GetNextGenericNode create() { - return GetNextGenericNodeGen.create(); - } - - @Specialization - protected int intVectorGeneric(RAbstractIntVector vector, IteratorData<?> iter, - @Cached("create()") GetDataAt.Int getDataAtNode) { - return getDataAtNode.get(vector, iter.store, iter.index); - } - - @Specialization - protected double doubleVectorGeneric(RAbstractDoubleVector vector, IteratorData<?> iter, - @Cached("create()") GetDataAt.Double getDataAtNode) { - return getDataAtNode.get(vector, iter.store, iter.index); - } - - @Specialization - protected String stringVectorGeneric(RAbstractStringVector vector, IteratorData<?> iter, - @Cached("create()") GetDataAt.String getDataAtNode) { - return getDataAtNode.get(vector, iter.store, iter.index); - } - - @Specialization - protected byte rawVectorGeneric(RAbstractRawVector vector, IteratorData<?> iter, - @Cached("create()") GetDataAt.Raw getDataAtNode) { - return getDataAtNode.get(vector, iter.store, iter.index); - } - - @Specialization - protected byte logicalVectorGeneric(RAbstractLogicalVector vector, IteratorData<?> iter, - @Cached("create()") GetDataAt.Logical getDataAtNode) { - return getDataAtNode.get(vector, iter.store, iter.index); - } - - @Specialization - protected RComplex complexVectorGeneric(RAbstractComplexVector vector, IteratorData<?> iter, - @Cached("create()") GetDataAt.Complex getDataAtNode) { - return getDataAtNode.get(vector, iter.store, iter.index); - } - } -} - -// Checkstyle: stop final class check -// Note: the VectorIterator cannot be final, it has inner subclasses, which probably confuses check -// style - -/** - * This node wraps 3 nodes needed to sequentially iterate a given vector and provides convenience - * methods to invoke those nodes: {@link #init(RAbstractVector)}, - * {@link #next(RAbstractVector, Object)} and {@link #hasNext(RAbstractVector, Object)}. - * - * To construct use factory methods from type specialized inner classes, e.g. {@link Int#create()}, - * or generic version if the iterated vector could be of any type {@link Generic#create()}. - * - * Iterator can wrap around, i.e. once the iteration ends, it starts again from the first element. - */ -public abstract class VectorIterator<T> extends Node { - - // Note: it could be worth adding a LoopConditionProfile, however, it must be shared between - // getIteratorNode and getNextNode - - @Child private GetIteratorNode getIteratorNode = GetIteratorNodeGen.create(); - @Child private HasNextNode hasNextNode; - @Child private GetNextNode getNextNode = GetNextNodeGen.create(); - private final boolean wrapAround; - - private VectorIterator(boolean wrapAround) { - this.wrapAround = wrapAround; - if (!wrapAround) { - hasNextNode = HasNextNodeGen.create(); - } - } - - public Object init(RAbstractVector vector) { - return getIteratorNode.execute(vector); - } - - public boolean hasNext(RAbstractVector vector, Object iterator) { - assert !wrapAround : "wrap-around iteration does not support hasNext"; - return hasNextNode.execute(vector, (IteratorData<?>) iterator); - } - - @SuppressWarnings("unchecked") - public T next(RAbstractVector vector, Object iterator) { - IteratorData<T> it = (IteratorData<T>) iterator; - assert it.index < it.length; - Object result = getNextNode.execute(vector, it); - if (wrapAround) { - it.index = Utils.incMod(it.index, it.length); - } else { - it.index++; - } - return (T) result; - } - - public static final class Generic extends VectorIterator<Object> { - - private Generic(boolean wrapAround) { - super(wrapAround); - } - - public static Generic create() { - return new Generic(false); - } - - public static Generic createWrapAround() { - return new Generic(true); - } - } - - public static final class Int extends VectorIterator<Integer> { - - public Int(boolean wrapAround) { - super(wrapAround); - } - - public static Int create() { - return new Int(false); - } - } - - public static final class Double extends VectorIterator<java.lang.Double> { - public Double(boolean wrapAround) { - super(wrapAround); - } - - public static Double create() { - return new Double(false); - } - - public static Double createWrapAround() { - return new Double(true); - } - } - - public static final class Logical extends VectorIterator<Byte> { - public Logical(boolean wrapAround) { - super(wrapAround); - } - - public static Logical create() { - return new Logical(false); - } - } - - public static final class Raw extends VectorIterator<Byte> { - public Raw(boolean wrapAround) { - super(wrapAround); - } - - public static Raw create() { - return new Raw(false); - } - } - - @ValueType - public static final class IteratorData<StoreT> { - public int index = 0; - public final StoreT store; - public final int length; - - public IteratorData(StoreT store, int length) { - this.store = store; - this.length = length; - } - - public boolean hasNativeMirror() { - return NativeDataAccess.isNativeMirror(store); - } - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReadAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReadAccess.java deleted file mode 100644 index f4d70cdf22da3fa256468fa2b6c9a5f407bd3acc..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReadAccess.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; -import com.oracle.truffle.r.runtime.data.RComplex; -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; - -/** - * Contains nodes that encapsulate {@link GetDataStore} and one of the nodes from {@link GetDataAt} - * as these are often used together. These are convenience wrappers to be used e.g. for a @Cached - * parameter. - */ -public abstract class VectorReadAccess extends VectorAccessAdapter { - - public abstract Object getDataAtAsObject(RAbstractVector vector, Object store, int index); - - @NodeInfo(cost = NodeCost.NONE) - public static final class Double extends VectorReadAccess { - @Child private GetDataAt.Double getDataAtNode = GetDataAt.Double.create(); - - public double getDataAt(RAbstractDoubleVector vec, Object store, int index) { - return getDataAtNode.get(vec, store, index); - } - - @Override - public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) { - return getDataAt((RAbstractDoubleVector) vector, store, index); - } - - public static Double create() { - return new Double(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class Int extends VectorReadAccess { - @Child private GetDataAt.Int getDataAtNode = GetDataAt.Int.create(); - - public int getDataAt(RAbstractIntVector vec, Object store, int index) { - return getDataAtNode.get(vec, store, index); - } - - @Override - public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) { - return getDataAt((RAbstractIntVector) vector, store, index); - } - - public static Int create() { - return new Int(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class Logical extends VectorReadAccess { - @Child private GetDataAt.Logical getDataAtNode = GetDataAt.Logical.create(); - - public byte getDataAt(RAbstractLogicalVector vec, Object store, int index) { - return getDataAtNode.get(vec, store, index); - } - - @Override - public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) { - return getDataAt((RAbstractLogicalVector) vector, store, index); - } - - public static Logical create() { - return new Logical(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class Complex extends VectorReadAccess { - @Child private GetDataAt.Complex getDataAtNode = GetDataAt.Complex.create(); - - public RComplex getDataAt(RAbstractComplexVector vec, Object store, int index) { - return getDataAtNode.get(vec, store, index); - } - - @Override - public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) { - return getDataAt((RAbstractComplexVector) vector, store, index); - } - - public static Complex create() { - return new Complex(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class String extends VectorReadAccess { - @Child private GetDataAt.String getDataAtNode = GetDataAt.String.create(); - - public java.lang.String getDataAt(RAbstractStringVector vec, Object store, int index) { - return getDataAtNode.get(vec, store, index); - } - - @Override - public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) { - return getDataAt((RAbstractStringVector) vector, store, index); - } - - public static String create() { - return new String(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class Raw extends VectorReadAccess { - @Child private GetDataAt.Raw getDataAtNode = GetDataAt.Raw.create(); - - public byte getDataAt(RAbstractRawVector vec, Object store, int index) { - return getDataAtNode.get(vec, store, index); - } - - @Override - public Object getDataAtAsObject(RAbstractVector vector, Object store, int index) { - return getDataAt((RAbstractRawVector) vector, store, index); - } - - public static Raw create() { - return new Raw(); - } - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReuse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReuse.java new file mode 100644 index 0000000000000000000000000000000000000000..88106a631e544dcb6f2e2885c4e67057aaa8945f --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorReuse.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.runtime.data.nodes; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.data.RSharingAttributeStorage; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; + +public final class VectorReuse extends Node { + + @Child private VectorAccess access; + + private final boolean isShareableClass; + private final boolean isTempOrNonShared; + private final boolean needsTemporary; + protected final boolean isGeneric; + protected final Class<? extends RAbstractVector> clazz; + + public VectorReuse(RAbstractVector vector, boolean needsTemporary, boolean isGeneric) { + this.isShareableClass = isGeneric ? false : vector instanceof RSharingAttributeStorage; + this.clazz = isGeneric ? null : vector.getClass(); + this.needsTemporary = needsTemporary; + this.isGeneric = isGeneric; + this.isTempOrNonShared = isShareableClass && isTempOrNonShared(vector); + } + + protected RAbstractVector cast(RAbstractVector value) { + return clazz.cast(value); + } + + public VectorAccess access(RAbstractVector result) { + return isGeneric ? result.slowPathAccess() : access; + } + + public boolean supports(RAbstractVector value) { + assert !isGeneric : "cannot call 'supports' on generic vector reuse"; + RSharingAttributeStorage.verify(value); + if (value.getClass() != clazz) { + return false; + } + if (access == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + access = insert(isTempOrNonShared ? value.access() : VectorAccess.createNew(value.getRType())); + } + if (!isShareableClass) { + return true; + } + if (isTempOrNonShared && !access.supports(value)) { + return false; + } + RSharingAttributeStorage vector = (RSharingAttributeStorage) cast(value); + return needsTemporary ? vector.isTemporary() == isTempOrNonShared : !vector.isShared() == isTempOrNonShared; + } + + @TruffleBoundary + private static RAbstractVector copyVector(RAbstractVector vector) { + return vector.copy(); + } + + private boolean isTempOrNonShared(RAbstractVector vector) { + return needsTemporary ? ((RSharingAttributeStorage) vector).isTemporary() : !((RSharingAttributeStorage) vector).isShared(); + } + + @SuppressWarnings("unchecked") + public <T extends RAbstractVector> T getResult(T vector) { + RAbstractVector result; + if (isGeneric) { + RSharingAttributeStorage.verify(vector); + if (vector instanceof RSharingAttributeStorage && isTempOrNonShared(vector)) { + result = vector; + } else { + result = copyVector(vector); + } + } else { + if (!isShareableClass || !isTempOrNonShared) { + result = cast(vector).copy(); + } else { + result = cast(vector); + } + } + return (T) result; + } + + public static VectorReuse createTemporaryGeneric() { + return new VectorReuse(null, true, true); + } + + public static VectorReuse createNonSharedGeneric() { + return new VectorReuse(null, false, true); + } + + public static VectorReuse createTemporary(RAbstractVector vector) { + return new VectorReuse(vector, true, false); + } + + public static VectorReuse createNonShared(RAbstractVector vector) { + return new VectorReuse(vector, false, false); + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorWriteAccess.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorWriteAccess.java deleted file mode 100644 index 8c8af336399fc53fedd2b6519b94420a18f6ab2a..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/nodes/VectorWriteAccess.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.truffle.r.runtime.data.nodes; - -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; -import com.oracle.truffle.r.runtime.data.RComplex; -import com.oracle.truffle.r.runtime.data.RComplexVector; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RLogicalVector; -import com.oracle.truffle.r.runtime.data.RRawVector; -import com.oracle.truffle.r.runtime.data.RStringVector; - -/** - * Contains nodes that encapsulate {@link GetDataStore} and one of the nodes from {@link SetDataAt} - * as these are often used together. These are convenience wrappers to be used e.g. for a @Cached - * parameter. - */ -public abstract class VectorWriteAccess { - @NodeInfo(cost = NodeCost.NONE) - public static final class Double extends VectorAccessAdapter { - @Child private SetDataAt.Double setDataAtNode = SetDataAt.Double.create(); - - public void setDataAt(RDoubleVector vector, Object store, int index, double value) { - setDataAtNode.setDataAt(vector, store, index, value); - } - - public static Double create() { - return new Double(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class Int extends VectorAccessAdapter { - @Child private SetDataAt.Int setDataAtNode = SetDataAt.Int.create(); - - public void setDataAt(RIntVector vector, Object store, int index, int value) { - setDataAtNode.setDataAt(vector, store, index, value); - } - - public static Int create() { - return new Int(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class Logical extends VectorAccessAdapter { - @Child private SetDataAt.Logical setDataAtNode = SetDataAt.Logical.create(); - - public void setDataAt(RLogicalVector vector, Object store, int index, byte value) { - setDataAtNode.setDataAt(vector, store, index, value); - } - - public static Logical create() { - return new Logical(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class Raw extends VectorAccessAdapter { - @Child private SetDataAt.Raw setDataAtNode = SetDataAt.Raw.create(); - - public void setDataAt(RRawVector vector, Object store, int index, byte value) { - setDataAtNode.setDataAt(vector, store, index, value); - } - - public static Raw create() { - return new Raw(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class String extends VectorAccessAdapter { - @Child private SetDataAt.String setDataAtNode = SetDataAt.String.create(); - - public void setDataAt(RStringVector vector, Object store, int index, java.lang.String value) { - setDataAtNode.setDataAt(vector, store, index, value); - } - - public static String create() { - return new String(); - } - } - - @NodeInfo(cost = NodeCost.NONE) - public static final class Complex extends VectorAccessAdapter { - @Child private SetDataAt.Complex setDataAtNode = SetDataAt.Complex.create(); - - public void setDataAt(RComplexVector vector, Object store, int index, RComplex value) { - setDataAtNode.setDataAt(vector, store, index, value); - } - - public static Complex create() { - return new Complex(); - } - } -} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java index 014af717bc7c428eaedd64e7b0459645f8206dba..ecfce5c1599cbf35bb9781ea96fa3c7f44c1d6d5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/REnvironment.java @@ -1147,6 +1147,7 @@ public abstract class REnvironment extends RAttributeStorage { } @Override + @TruffleBoundary public void put(String key, Object value) throws PutException { throw new PutException(RError.Message.ENV_ASSIGN_EMPTY); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java index 1175bc95eb911cab80507e441c3610bd2a6e71cb..b2b566a04b42acfad7ea08777d82f7b3882d1c6a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/CRFFI.java @@ -56,6 +56,8 @@ 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.nodes.VectorAccess; +import com.oracle.truffle.r.runtime.data.nodes.VectorAccess.SequentialIterator; import com.oracle.truffle.r.runtime.nodes.RBaseNode; import sun.misc.Unsafe; @@ -390,12 +392,15 @@ final class RawWrapper extends TemporaryWrapper { @TruffleBoundary public long allocate() { RAbstractRawVector v = (RAbstractRawVector) vector; - int length = v.getLength(); - long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_BYTE_INDEX_SCALE); - for (int i = 0; i < length; i++) { - UnsafeAdapter.UNSAFE.putByte(memory + (i * Unsafe.ARRAY_BYTE_INDEX_SCALE), v.getRawDataAt(i)); + VectorAccess access = v.slowPathAccess(); + try (SequentialIterator iter = access.access(v)) { + int length = access.getLength(iter); + long memory = UnsafeAdapter.UNSAFE.allocateMemory(length * Unsafe.ARRAY_BYTE_INDEX_SCALE); + while (access.next(iter)) { + UnsafeAdapter.UNSAFE.putByte(memory + (iter.getIndex() * Unsafe.ARRAY_BYTE_INDEX_SCALE), access.getRaw(iter)); + } + return memory; } - return memory; } @Override diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java index bb59cfc10cae05de573a6806be5509dc8c48a24c..43bffb637f5f30e311b4d1be0b663c15ddab6921 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/ForeignArray2R.java @@ -43,9 +43,16 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.r.runtime.FastROptions; import com.oracle.truffle.r.runtime.RError; +import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RForeignBooleanWrapper; +import com.oracle.truffle.r.runtime.data.RForeignDoubleWrapper; +import com.oracle.truffle.r.runtime.data.RForeignIntWrapper; +import com.oracle.truffle.r.runtime.data.RForeignListWrapper; +import com.oracle.truffle.r.runtime.data.RForeignStringWrapper; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RVector; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; @@ -59,9 +66,10 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode; public abstract class ForeignArray2R extends RBaseNode { @Child protected Node hasSize = Message.HAS_SIZE.createNode(); + @Child protected Node getSize = Message.GET_SIZE.createNode(); @Child private Foreign2R foreign2R; @Child private ForeignArray2R foreignArray2R; - @Child private Node read; + @Child private Node read = Message.READ.createNode(); @Child private Node isNull; @Child private Node isBoxed; @Child private Node unbox; @@ -91,25 +99,54 @@ public abstract class ForeignArray2R extends RBaseNode { * */ public Object convert(Object obj, boolean recursive) { - Object result = execute(obj, recursive, null, 0); - if (result instanceof ForeignArrayData) { - ForeignArrayData arrayData = (ForeignArrayData) result; - if (arrayData.elements.isEmpty()) { - return RDataFactory.createList(); + if (FastROptions.ForeignObjectWrappers.getBooleanValue()) { + if (isForeignArray(obj)) { + TruffleObject truffleObject = (TruffleObject) obj; + try { + int size = (int) ForeignAccess.sendGetSize(getSize, truffleObject); + if (size == 0) { + return new RForeignListWrapper(truffleObject); + } else { + Object firstElement = ForeignAccess.sendRead(read, truffleObject, 0); + switch (InteropTypeCheck.determineType(firstElement)) { + case BOOLEAN: + return new RForeignBooleanWrapper(truffleObject); + case DOUBLE: + return new RForeignDoubleWrapper(truffleObject); + case INTEGER: + return new RForeignIntWrapper(truffleObject); + case STRING: + return new RForeignStringWrapper(truffleObject); + default: + return new RForeignListWrapper(truffleObject); + } + } + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw RInternalError.shouldNotReachHere(e); + } + } else { + return obj; } - return asAbstractVector(arrayData); + } else { + Object result = execute(obj, recursive, null, 0); + if (result instanceof ForeignArrayData) { + ForeignArrayData arrayData = (ForeignArrayData) result; + if (arrayData.elements.isEmpty()) { + return RDataFactory.createList(); + } + return asAbstractVector(arrayData); + } + return result; } - return result; } protected abstract Object execute(Object obj, boolean recursive, ForeignArrayData arrayData, int depth); @Specialization(guards = {"isForeignArray(obj)"}) @TruffleBoundary - protected ForeignArrayData doArray(TruffleObject obj, boolean recursive, ForeignArrayData arrayData, int depth, - @Cached("GET_SIZE.createNode()") Node getSize) { + protected ForeignArrayData doArray(TruffleObject obj, boolean recursive, ForeignArrayData arrayData, int depth) { try { - return collectArrayElements(arrayData == null ? new ForeignArrayData() : arrayData, obj, recursive, getSize, depth); + return collectArrayElements(arrayData == null ? new ForeignArrayData() : arrayData, obj, recursive, depth); } catch (UnsupportedMessageException | UnknownIdentifierException e) { throw error(RError.Message.GENERIC, "error while converting array: " + e.getMessage()); } @@ -132,7 +169,7 @@ public abstract class ForeignArray2R extends RBaseNode { return obj; } - private ForeignArrayData collectArrayElements(ForeignArrayData arrayData, TruffleObject obj, boolean recursive, Node getSize, int depth) + private ForeignArrayData collectArrayElements(ForeignArrayData arrayData, TruffleObject obj, boolean recursive, int depth) throws UnsupportedMessageException, UnknownIdentifierException { int size = (int) ForeignAccess.sendGetSize(getSize, obj); @@ -152,10 +189,6 @@ public abstract class ForeignArray2R extends RBaseNode { return arrayData; } for (int i = 0; i < size; i++) { - if (read == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - read = insert(Message.READ.createNode()); - } Object element = ForeignAccess.sendRead(read, obj, i); if (recursive && (isForeignArray(element, hasSize) || isJavaIterable(element))) { recurse(arrayData, element, depth); @@ -387,6 +420,20 @@ public abstract class ForeignArray2R extends RBaseNode { private RType type = null; + public static RType determineType(Object value) { + if (value instanceof Boolean) { + return RType.BOOLEAN; + } else if (value instanceof Byte || value instanceof Integer || value instanceof Short) { + return RType.INTEGER; + } else if (value instanceof Double || value instanceof Float || value instanceof Long) { + return RType.DOUBLE; + } else if (value instanceof Character || value instanceof String) { + return RType.STRING; + } else { + return RType.NONE; + } + } + public RType checkForeign(Object value) { if (value instanceof Boolean) { setType(RType.BOOLEAN); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/TruffleObjectConverter.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/TruffleObjectConverter.java index 2bb74514a080165169958abc0501ef2d95c93107..e939f44b7a402218b413034d9093cf367251f961 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/TruffleObjectConverter.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/TruffleObjectConverter.java @@ -26,29 +26,18 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.interop.UnknownIdentifierException; -import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RAttributeStorage; -import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RDataFactory; -import com.oracle.truffle.r.runtime.data.RDoubleVector; -import com.oracle.truffle.r.runtime.data.RIntVector; -import com.oracle.truffle.r.runtime.data.RList; -import com.oracle.truffle.r.runtime.data.RLogicalVector; +import com.oracle.truffle.r.runtime.data.RForeignBooleanWrapper; +import com.oracle.truffle.r.runtime.data.RForeignDoubleWrapper; +import com.oracle.truffle.r.runtime.data.RForeignIntWrapper; +import com.oracle.truffle.r.runtime.data.RForeignListWrapper; +import com.oracle.truffle.r.runtime.data.RForeignNamedListWrapper; +import com.oracle.truffle.r.runtime.data.RForeignStringWrapper; import com.oracle.truffle.r.runtime.data.RStringVector; -import com.oracle.truffle.r.runtime.data.RTypedValue; -import com.oracle.truffle.r.runtime.data.RVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; -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.RAbstractListVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; -import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public final class TruffleObjectConverter { @@ -58,93 +47,13 @@ public final class TruffleObjectConverter { private Node isBoxedNode = com.oracle.truffle.api.interop.Message.IS_BOXED.createNode(); private Node unboxNode = com.oracle.truffle.api.interop.Message.UNBOX.createNode(); private Node keysNode = com.oracle.truffle.api.interop.Message.KEYS.createNode(); - private Foreign2R foreign2R = Foreign2R.create(); - - public TruffleObjectConverter() { - } public Node[] getSubNodes() { - return new Node[]{ - hasSizeNode, getSizeNode, readNode, isBoxedNode, unboxNode, keysNode, foreign2R - }; + return new Node[]{hasSizeNode, getSizeNode, readNode, isBoxedNode, unboxNode, keysNode}; } @TruffleBoundary public Object convert(TruffleObject obj) { - class RStringWrapper extends TruffleObjectWrapper implements RAbstractStringVector { - final TruffleObject object; - - RStringWrapper(int length, TruffleObject object) { - super(length); - this.object = object; - } - - @Override - @TruffleBoundary - public Object getDataAtAsObject(int index) { - return getDataAt(index); - } - - @Override - @TruffleBoundary - public String getDataAt(int index) { - Object value; - try { - value = ForeignAccess.sendRead(readNode, object, index); - return String.valueOf(foreign2R.execute(value)); - } catch (UnknownIdentifierException | UnsupportedMessageException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - - @Override - @TruffleBoundary - public RStringVector materialize() { - throw RInternalError.shouldNotReachHere(); - } - } - class RListWrapper extends TruffleObjectWrapper implements RAbstractListVector { - - private final RStringVector names; - - RListWrapper(int length, RStringVector names) { - super(length); - this.names = names; - if (names != null) { - DynamicObject attrs = RAttributesLayout.createNames(names); - initAttributes(attrs); - } - } - - @Override - @TruffleBoundary - public Object getDataAtAsObject(int index) { - return getDataAt(index); - } - - @Override - @TruffleBoundary - public Object getDataAt(int index) { - try { - Object value = ForeignAccess.sendRead(readNode, obj, names != null ? names.getDataAt(index) : index); - return foreign2R.execute(value); - } catch (UnknownIdentifierException | UnsupportedMessageException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - - @Override - @TruffleBoundary - public RStringVector getNames() { - return names; - } - - @Override - @TruffleBoundary - public RList materialize() { - throw RInternalError.shouldNotReachHere(); - } - } try { if (ForeignAccess.sendHasSize(hasSizeNode, obj)) { int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, obj); @@ -160,102 +69,15 @@ public final class TruffleObjectConverter { } switch (typeCheck.getType()) { case BOOLEAN: - class RLogicalWrapper extends TruffleObjectWrapper implements RAbstractLogicalVector { - - RLogicalWrapper(int length) { - super(length); - } - - @Override - @TruffleBoundary - public Object getDataAtAsObject(int index) { - return getDataAt(index); - } - - @Override - @TruffleBoundary - public byte getDataAt(int index) { - try { - Object value = ForeignAccess.sendRead(readNode, obj, index); - return (byte) foreign2R.execute(value); - } catch (UnknownIdentifierException | UnsupportedMessageException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - - @Override - @TruffleBoundary - public RLogicalVector materialize() { - throw RInternalError.shouldNotReachHere(); - } - } - return new RLogicalWrapper(size); + return new RForeignBooleanWrapper(obj); case INTEGER: - class RIntWrapper extends TruffleObjectWrapper implements RAbstractIntVector { - - RIntWrapper(int length) { - super(length); - } - - @Override - @TruffleBoundary - public Object getDataAtAsObject(int index) { - return getDataAt(index); - } - - @Override - @TruffleBoundary - public int getDataAt(int index) { - try { - Object value = ForeignAccess.sendRead(readNode, obj, index); - return ((Number) foreign2R.execute(value)).intValue(); - } catch (UnknownIdentifierException | UnsupportedMessageException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - - @Override - @TruffleBoundary - public RIntVector materialize() { - throw RInternalError.shouldNotReachHere(); - } - } - return new RIntWrapper(size); + return new RForeignIntWrapper(obj); case DOUBLE: - class RDoubleWrapper extends TruffleObjectWrapper implements RAbstractDoubleVector { - - RDoubleWrapper(int length) { - super(length); - } - - @Override - @TruffleBoundary - public Object getDataAtAsObject(int index) { - return getDataAt(index); - } - - @Override - @TruffleBoundary - public double getDataAt(int index) { - try { - Object value = ForeignAccess.sendRead(readNode, obj, index); - return ((Number) foreign2R.execute(value)).doubleValue(); - } catch (UnknownIdentifierException | UnsupportedMessageException e) { - throw RInternalError.shouldNotReachHere(e); - } - } - - @Override - @TruffleBoundary - public RDoubleVector materialize() { - throw RInternalError.shouldNotReachHere(); - } - } - return new RDoubleWrapper(size); + return new RForeignDoubleWrapper(obj); case STRING: - return new RStringWrapper(size, obj); + return new RForeignStringWrapper(obj); case NONE: - return new RListWrapper(size, null); + return new RForeignListWrapper(obj); default: throw RInternalError.shouldNotReachHere(); } @@ -263,7 +85,7 @@ public final class TruffleObjectConverter { TruffleObject keys = (TruffleObject) ForeignAccess.send(keysNode, obj); if (keys != null) { int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, keys); - RAbstractStringVector abstractNames = new RStringWrapper(size, keys); + RAbstractStringVector abstractNames = new RForeignStringWrapper(keys); String[] namesData = new String[size]; boolean namesComplete = true; for (int i = 0; i < size; i++) { @@ -272,141 +94,11 @@ public final class TruffleObjectConverter { } RStringVector names = RDataFactory.createStringVector(namesData, namesComplete); - return new RListWrapper(size, names); + return new RForeignNamedListWrapper(obj, names); } } catch (InteropException e) { // nothing to do } return obj; } - - private abstract static class TruffleObjectWrapper extends RAttributeStorage implements RAbstractVector { - - private final int length; - - TruffleObjectWrapper(int length) { - this.length = length; - } - - @Override - public RAbstractVector copy() { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public RVector<?> copyResized(int size, boolean fillNA) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public RAbstractVector copyWithNewDimensions(int[] newDimensions) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public RVector<?> copyResizedWithDimensions(int[] newDimensions, boolean fillNA) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public RAbstractVector copyDropAttributes() { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public RVector<?> createEmptySameType(int newLength, boolean newIsComplete) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public boolean isMatrix() { - return false; - } - - @Override - public boolean isArray() { - return false; - } - - @Override - public boolean checkCompleteness() { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public void setComplete(boolean complete) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public boolean isComplete() { - return false; - } - - @Override - public int getLength() { - return length; - } - - @Override - public RAbstractContainer resize(int size) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public boolean hasDimensions() { - return false; - } - - @Override - public int[] getDimensions() { - return null; - } - - @Override - public void setDimensions(int[] newDimensions) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public RTypedValue getNonShared() { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public RStringVector getNames() { - return null; - } - - @Override - public final void setNames(RStringVector newNames) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public RList getDimNames() { - return null; - } - - @Override - public void setDimNames(RList newDimNames) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public Object getRowNames() { - return null; - } - - @Override - public void setRowNames(RAbstractVector rowNames) { - throw RInternalError.shouldNotReachHere(); - } - - @Override - public ForeignAccess getForeignAccess() { - throw RInternalError.shouldNotReachHere(); - } - } - } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RandomFunctions.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RandomFunctions.java index 736cf4b3bd9700ea33d24061aa050f83024a7b2b..3c4f0e22243010090b9fbdf03ed3a7c07449fe6b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RandomFunctions.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/RandomFunctions.java @@ -47,11 +47,11 @@ public class RandomFunctions { } } - public abstract static class RandFunction1_Double extends RandFunction2_Double { + public abstract static class RandFunction1_Double extends RandFunction3_Double { public abstract double execute(double a, RandomNumberProvider rand); @Override - public final double execute(double a, double b, RandomNumberProvider rand) { + public final double execute(double a, double b, double c, RandomNumberProvider rand) { return execute(a, rand); } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java index 1acc54576bcaa9a82c3d37a02ccec3d8b01fa094..822b14b94a898fa8d70e1c109de5f68dc0ca177a 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/nmath/distr/RMultinom.java @@ -18,7 +18,8 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.nodes.ReadAccessor; +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.nmath.RandomFunctions.RandomNumberProvider; public final class RMultinom { @@ -32,7 +33,7 @@ public final class RMultinom { * prob[j]) , sum_j rN[j] == n, sum_j prob[j] == 1. */ @TruffleBoundary - public static boolean rmultinom(int nIn, ReadAccessor.Double prob, int maxK, int[] rN, int rnStartIdx, RandomNumberProvider rand, Rbinom rbinom) { + public static boolean rmultinom(int nIn, SequentialIterator probsIter, VectorAccess probsAccess, double sum, int[] rN, int rnStartIdx, RandomNumberProvider rand, Rbinom rbinom) { /* * This calculation is sensitive to exact values, so we try to ensure that the calculations * are as accurate as possible so different platforms are more likely to give the same @@ -40,6 +41,7 @@ public final class RMultinom { */ int n = nIn; + int maxK = probsAccess.getLength(probsIter); if (RRuntime.isNA(maxK) || maxK < 1 || RRuntime.isNA(n) || n < 0) { if (rN.length > rnStartIdx) { rN[rnStartIdx] = RRuntime.INT_NA; @@ -52,8 +54,9 @@ public final class RMultinom { * shorter and drop that check ! */ /* LDOUBLE */double pTot = 0.; - for (int k = 0; k < maxK; k++) { - double pp = prob.getDataAt(k); + probsAccess.reset(probsIter); + for (int k = 0; probsAccess.next(probsIter); k++) { + double pp = probsAccess.getDouble(probsIter) / sum; if (!Double.isFinite(pp) || pp < 0. || pp > 1.) { rN[rnStartIdx + k] = RRuntime.INT_NA; return false; @@ -74,9 +77,10 @@ public final class RMultinom { } /* Generate the first K-1 obs. via binomials */ - for (int k = 0; k < maxK - 1; k++) { + probsAccess.reset(probsIter); + for (int k = 0; probsAccess.next(probsIter) && k < maxK - 1; k++) { /* (p_tot, n) are for "remaining binomial" */ - /* LDOUBLE */double probK = prob.getDataAt(k); + /* LDOUBLE */double probK = probsAccess.getDouble(probsIter) / sum; if (probK != 0.) { double pp = probK / pTot; // System.out.printf("[%d] %.17f\n", k + 1, pp); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java index 304d26eb4bd072fc48316aab7e49328df60f87a5..b7883f38067abbca3ed847c407596f6df09b8ad6 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/BinaryArithmetic.java @@ -124,6 +124,7 @@ public abstract class BinaryArithmetic extends Operation { public static final class Add extends BinaryArithmetic { + @CompilationFinal private boolean introducesOverflow = false; @CompilationFinal private boolean introducesNA = false; public Add() { @@ -137,17 +138,22 @@ public abstract class BinaryArithmetic extends Operation { @Override public boolean introducesNA() { - return introducesNA; + return introducesNA || introducesOverflow; } @Override public int op(int left, int right) { - if (!introducesNA) { + if (!introducesOverflow) { try { - return Math.addExact(left, right); + int result = Math.addExact(left, right); + // NAs can also be introduced without a 32-bit overflow + if (!introducesNA && result == RRuntime.INT_NA) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + introducesNA = true; + } } catch (ArithmeticException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); - introducesNA = true; + introducesOverflow = true; } } // Borrowed from ExactMath @@ -176,6 +182,7 @@ public abstract class BinaryArithmetic extends Operation { public static final class Subtract extends BinaryArithmetic { + @CompilationFinal private boolean introducesOverflow = false; @CompilationFinal private boolean introducesNA = false; public Subtract() { @@ -189,17 +196,23 @@ public abstract class BinaryArithmetic extends Operation { @Override public boolean introducesNA() { - return introducesNA; + return introducesNA || introducesOverflow; } @Override public int op(int left, int right) { - if (!introducesNA) { + if (!introducesOverflow) { try { - return Math.subtractExact(left, right); + int result = Math.subtractExact(left, right); + // NAs can also be introduced without a 32-bit overflow + if (!introducesNA && result == RRuntime.INT_NA) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + introducesNA = true; + } + return result; } catch (ArithmeticException e) { CompilerDirectives.transferToInterpreterAndInvalidate(); - introducesNA = true; + introducesOverflow = true; } } // Borrowed from ExactMath diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java index cbf0f6f606a1d55a6229c0d257aa2f80a02c143b..31ce4935a26c0e7554abe576565453f55d156ab9 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ops/na/NACheck.java @@ -120,6 +120,17 @@ public final class NACheck { return false; } + public boolean check(double real, double imag) { + if (state != NO_CHECK && RRuntime.isNA(real, imag)) { + if (state == CHECK_DEOPT) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + state = CHECK; + } + return true; + } + return false; + } + public void seenNA() { if (state != CHECK) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -161,6 +172,7 @@ public final class NACheck { } public boolean checkListElement(Object value) { + assert value != null; if (state != NO_CHECK && value == RNull.instance) { if (state == CHECK_DEOPT) { CompilerDirectives.transferToInterpreterAndInvalidate(); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ArithmeticWhiteList.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ArithmeticWhiteList.java index 01d39683e7544b3e00ad15e8207550334b1970f2..336127e33bc19ebae2e870a0cbcd185bb351ff44 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ArithmeticWhiteList.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ArithmeticWhiteList.java @@ -37,7 +37,6 @@ public class ArithmeticWhiteList { static { WHITELIST.add("{ abs((-0-1i)/(0+0i)) }", "[1] NaN\n", "[1] Inf\n"); WHITELIST.add("{ abs((-1-0i)/(0+0i)) }", "[1] NaN\n", "[1] Inf\n"); - WHITELIST.add("{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = FALSE)}", "[1] NaN+NaNi 4.5+7.5i\n", "[1] NaN+0.0i 4.5+7.5i\n"); WHITELIST.add("{ ((0+1i)/0) * ((0+1i)/0) }", "[1] NaN+NaNi\n", "[1] -Inf+NaNi\n"); WHITELIST.add("{ ((0-1i)/0) * ((-1-1i)/0) }", "[1] NaN+NaNi\n", "[1] -Inf+Infi\n"); WHITELIST.add("{ ((0-1i)/0) * ((0+1i)/0) }", "[1] NaN+NaNi\n", "[1] Inf+NaNi\n"); @@ -55,7 +54,6 @@ public class ArithmeticWhiteList { WHITELIST.add("{ -((0+1i)/0) }", "[1] NaN+NaNi\n", "[1] NaN-Infi\n"); WHITELIST.add("{ -((1+0i)/0) }", "[1] NaN+NaNi\n", "[1] -Inf+NaNi\n"); WHITELIST.add("{ -c((1+0i)/0,2) }", "[1] NaN+NaNi -2+ 0i\n", "[1] -Inf+NaNi -2+ 0i\n"); - WHITELIST.add("x <- c(NaN, 3+2i); xre <- Re(x); xim <- (0+1i) * Im(x); xre + xim", "[1] NaN+NaNi 3+ 2i\n", "[1] NaN+0i 3+2i\n"); WHITELIST.add("{ c(0/0+1i,2+1i) == c(1+1i,2+1i) }", "[1] FALSE TRUE\n", "[1] NA TRUE\n"); WHITELIST.add("{ c(1+1i,2+1i) == c(0/0+1i,2+1i) }", "[1] FALSE TRUE\n", "[1] NA TRUE\n"); WHITELIST.add("exp(-abs((0+1i)/(0+0i)))", "[1] NaN\n", "[1] 0\n"); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 385781ccdccd1a4173badf68d4628fad73b38392..1baf7568d6d31e56b7361ec6b1a7c9ed1fc7a4e7 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -3221,6 +3221,38 @@ In anyDuplicated.default(c(1L, 2L, 1L, 1L, 3L, 2L), incomparables = "cat") : #anyNA(c(1, NA, 3), recursive = TRUE) [1] TRUE +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(1, NA)) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(1, NA), recursive = TRUE) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = NA)) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = NA), recursive = TRUE) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = NA, b = 'a')) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = NA, b = 'a'), recursive = TRUE) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = c('asdf', NA), b = 'a')) +[1] FALSE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = c('asdf', NA), b = 'a'), recursive = TRUE) +[1] TRUE + ##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# #anyNA(list(a = c(1, 2, 3), b = 'a')) [1] FALSE @@ -3229,6 +3261,10 @@ In anyDuplicated.default(c(1L, 2L, 1L, 1L, 3L, 2L), incomparables = "cat") : #anyNA(list(a = c(1, 2, 3), b = 'a'), recursive = TRUE) [1] FALSE +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = c(1, 2, 3), b = list(NA, 'a')), recursive = TRUE) +[1] TRUE + ##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# #anyNA(list(a = c(1, NA, 3), b = 'a')) [1] FALSE @@ -3237,6 +3273,14 @@ In anyDuplicated.default(c(1L, 2L, 1L, 1L, 3L, 2L), incomparables = "cat") : #anyNA(list(a = c(1, NA, 3), b = 'a'), recursive = TRUE) [1] TRUE +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = c(NA, 3), b = 'a')) +[1] FALSE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_anyNA.testanyNA3# +#anyNA(list(a = c(NA, 3), b = 'a'), recursive = TRUE) +[1] TRUE + ##com.oracle.truffle.r.test.builtins.TestBuiltin_aperm.testAperm# #{ a = array(1:24,c(2,3,4)); b = aperm(a); c(dim(b)[1],dim(b)[2],dim(b)[3]) } [1] 4 3 2 @@ -9955,6 +9999,9 @@ Error in attributes(x) <- 44 : attributes must be a list or NULL ##com.oracle.truffle.r.test.builtins.TestBuiltin_attributesassign.testArgsCasts# #x <- 42; attributes(x) <- NULL +##com.oracle.truffle.r.test.builtins.TestBuiltin_attributesassign.testArgsCasts# +#x <- 42; attributes(x) <- list() + ##com.oracle.truffle.r.test.builtins.TestBuiltin_attributesassign.testattributesassign1#Ignored.ImplementationError# #argv <- list(NULL, NULL);`attributes<-`(argv[[1]],argv[[2]]); NULL @@ -11395,7 +11442,7 @@ $Residuals #argv <- list(structure(1208822400, class = c('POSIXct', 'POSIXt')), structure(1209168000, class = c('POSIXct', 'POSIXt')));c(argv[[1]],argv[[2]]); [1] "2008-04-22 GMT" "2008-04-26 GMT" -##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testc14#Ignored.OutputFormatting# +##com.oracle.truffle.r.test.builtins.TestBuiltin_c.testc14# #argv <- list(`Grand mean` = structure(103.87323943662, class = 'mtable'), structure(list(N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('N', 'V:N')));c(argv[[1]],argv[[2]]); [[1]] [1] 103.8732 @@ -24892,7 +24939,7 @@ character(0) #argv <- list(c('1', '2', NA), 0L, '\'', 0L, FALSE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]])) [1] "'1'" "'2'" NA -##com.oracle.truffle.r.test.builtins.TestBuiltin_encodeString.testencodeString10#Ignored.ImplementationError# +##com.oracle.truffle.r.test.builtins.TestBuiltin_encodeString.testencodeString10# #argv <- list('\'class\' is a reserved slot name and cannot be redefined', 0L, '\'', 0L, FALSE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]])) [1] "'\\'class\\' is a reserved slot name and cannot be redefined'" @@ -24923,7 +24970,7 @@ character(0) #argv <- list(c('NA', 'a', 'b', 'c', 'd', NA), 0L, '', 0L, TRUE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]])) [1] "NA" "a" "b" "c" "d" "<NA>" -##com.oracle.truffle.r.test.builtins.TestBuiltin_encodeString.testencodeString7#Ignored.ImplementationError# +##com.oracle.truffle.r.test.builtins.TestBuiltin_encodeString.testencodeString7# #argv <- list('ab\bc\ndef', 0L, '', 0L, TRUE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]])) [1] "ab\\bc\\ndef" @@ -28333,7 +28380,7 @@ Error: 'x' must be a character vector #argv <- list('Report Information on C Stack Size and Usage', 'UTF-8', '', 'byte', FALSE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]])) [1] "Report Information on C Stack Size and Usage" -##com.oracle.truffle.r.test.builtins.TestBuiltin_iconv.testiconv2#Ignored.ImplementationError# +##com.oracle.truffle.r.test.builtins.TestBuiltin_iconv.testiconv2# #argv <- list('façile' , 'latin1', 'ASCII', NA_character_, TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]])) [1] NA @@ -28408,7 +28455,7 @@ character(0) #argv <- list(list(), 'latin1', 'ASCII', NA_character_, TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]])) character(0) -##com.oracle.truffle.r.test.builtins.TestBuiltin_iconv.testiconv7#Ignored.ImplementationError# +##com.oracle.truffle.r.test.builtins.TestBuiltin_iconv.testiconv7# #argv <- list('façile' , 'latin1', 'ASCII', '', TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]])) [1] "faile" @@ -28512,7 +28559,7 @@ attr(,"Rd_tag") #identical(NaN, NaN, num.eq=T, single.NA=T) [1] TRUE -##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#Ignored.ImplementationError# +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical# #{ f1 <- function() {}; f2 <- function() {}; identical(f1, f2) } [1] TRUE @@ -28540,7 +28587,7 @@ attr(,"Rd_tag") #{ identical(1L,1) } [1] FALSE -##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#Ignored.ImplementationError# +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical# #{ identical(function() 42, function() 42) } [1] TRUE @@ -34491,7 +34538,7 @@ attr(,"class")attr(,"package") [1] "methods" -##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testlist33#Ignored.OutputFormatting# +##com.oracle.truffle.r.test.builtins.TestBuiltin_list.testlist33# #argv <- list(tables = structure(list(`Grand mean` = 103.87323943662, N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('Grand mean', 'N', 'V:N')), n = structure(list(N = structure(c(17, 18, 18, 18), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N')), `V:N` = structure(c(6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')))), .Names = c('N', 'V:N')));list(argv[[1]],argv[[2]]); [[1]] [[1]]$`Grand mean` @@ -39080,7 +39127,7 @@ integer(0) #argv <- structure(list(x = structure(c(31, NA, NA, 31), units = 'days', class = 'difftime'), na.rm = TRUE), .Names = c('x', 'na.rm'));do.call('mean', argv) Time difference of 31 days -##com.oracle.truffle.r.test.builtins.TestBuiltin_mean.testmean2#Ignored.ImplementationError# +##com.oracle.truffle.r.test.builtins.TestBuiltin_mean.testmean2# #argv <- list(c(0.104166666666667, 0.285714285714286, 0.285714285714286, NA)); .Internal(mean(argv[[1]])) [1] NA @@ -45283,7 +45330,7 @@ attr(,"class") #argv <- list(181L, 3.14159265358979);`*`(argv[[1]],argv[[2]]); [1] 568.6283 -##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testoperators39#Ignored.OutputFormatting# +##com.oracle.truffle.r.test.builtins.TestBuiltin_operators.testoperators39# #argv <- list(structure(c(-24.5833333333333, -5.08333333333333, 10.25, 19.4166666666667), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), strata = structure('Within', .Names = 'N'), class = 'mtable'), structure(103.972222222222, class = 'mtable'));`+`(argv[[1]],argv[[2]]); N 0.0cwt 0.2cwt 0.4cwt 0.6cwt @@ -48198,105 +48245,237 @@ sex -1.65487 0.483 0.38527 11.74 1.0 0.00061 frailty(id, dist = 't', c 20.33 13.9 0.12000 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#prod() +#prod(1) [1] 1 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#prod(complex()) -[1] 1+0i +#prod(1,2,3,4) +[1] 24 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#prod(numeric()) +#prod(1,2,3,4,na.rm=FALSE) +[1] 24 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(1,2,3,4,na.rm=TRUE) +[1] 24 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(1,FALSE) +[1] 0 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(1,FALSE,na.rm=FALSE) +[1] 0 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(1,FALSE,na.rm=TRUE) +[1] 0 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(1,na.rm=FALSE) [1] 1 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{ foo <- function(...) prod(...); foo(); } +#prod(1,na.rm=TRUE) [1] 1 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod('a')} -Error in prod("a") : invalid 'type' (character) of argument +#prod(1L,NA,5+3i) +[1] NA ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod()} -[1] 1 +#prod(1L,NA,5+3i,na.rm=FALSE) +[1] NA ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(2+3i,42)} -[1] 84+126i +#prod(1L,NA,5+3i,na.rm=TRUE) +[1] 5+3i ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(2+3i,42+5i)} -[1] 69+136i +#prod(2,TRUE) +[1] 2 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(2+3i,c())} -[1] 2+3i +#prod(2,TRUE,na.rm=FALSE) +[1] 2 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(42,2+3i)} -[1] 84+126i +#prod(2,TRUE,na.rm=TRUE) +[1] 2 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(4+0i,6,NA) +[1] NA ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(NULL)} +#prod(4+0i,6,NA,na.rm=FALSE) +[1] NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(4+0i,6,NA,na.rm=TRUE) +[1] 24+0i + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(4L) +[1] 4 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(4L,na.rm=FALSE) +[1] 4 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(4L,na.rm=TRUE) +[1] 4 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(FALSE) +[1] 0 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(FALSE,na.rm=FALSE) +[1] 0 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(FALSE,na.rm=TRUE) +[1] 0 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(NA,c(1,2,3)) +[1] NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(NA,c(1,2,3),na.rm=FALSE) +[1] NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(NA,c(1,2,3),na.rm=TRUE) +[1] 6 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(NA_integer_) +[1] NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(NA_integer_,na.rm=FALSE) +[1] NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(NA_integer_,na.rm=TRUE) [1] 1 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c())} +#prod(TRUE) [1] 1 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(),c())} +#prod(TRUE,na.rm=FALSE) [1] 1 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(1+2i))} -[1] 1+2i +#prod(TRUE,na.rm=TRUE) +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(c(1,2,NA),NA) +[1] NA + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(c(1,2,NA),NA,na.rm=FALSE) +[1] NA ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(1+2i, 2+3i))} -[1] -4+7i +#prod(c(1,2,NA),NA,na.rm=TRUE) +[1] 2 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(1+2i,1+3i,1+45i))} -[1] -230-220i +#prod(c(2,4)) +[1] 8 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(1,2,3,4,5))} -[1] 120 +#prod(c(2,4),na.rm=FALSE) +[1] 8 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(2,4))} +#prod(c(2,4),na.rm=TRUE) [1] 8 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(2,4,3))} +#prod(c(2,4,3)) [1] 24 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(TRUE, FALSE))} -[1] 0 +#prod(c(2,4,3),na.rm=FALSE) +[1] 24 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(c(TRUE, TRUE))} -[1] 1 +#prod(c(2,4,3),na.rm=TRUE) +[1] 24 ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# -#{prod(list())} -Error in prod(list()) : invalid 'type' (list) of argument +#prod(c(2,4,NA)) +[1] NA -##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa# -#{prod(c(1,2,3,4,5,NA),FALSE)} +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(c(2,4,NA),na.rm=FALSE) [1] NA -##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa# -#{prod(c(2,4,3,NA),TRUE)} +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(c(2,4,NA),na.rm=TRUE) +[1] 8 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(c(NA,2L,4L)) [1] NA -##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProdNa# -#{prod(c(2,4,NA))} +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(c(NA,2L,4L),na.rm=FALSE) [1] NA +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(c(NA,2L,4L),na.rm=TRUE) +[1] 8 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(complex(),numeric()) +[1] 1+0i + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(complex(),numeric(),na.rm=FALSE) +[1] 1+0i + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(complex(),numeric(),na.rm=TRUE) +[1] 1+0i + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(numeric()) +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(numeric(),na.rm=FALSE) +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(numeric(),na.rm=TRUE) +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(numeric(),numeric()) +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(numeric(),numeric(),na.rm=FALSE) +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#prod(numeric(),numeric(),na.rm=TRUE) +[1] 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testProd# +#{ foo <- function(...) prod(...); foo(); } +[1] 1 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_prod.testprod1# #argv <- list(9L);prod(argv[[1]]); [1] 9 @@ -48880,7 +49059,7 @@ NULL #range(c(T, F, NA, NA, T)) [1] NA NA -##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithLogical# +##com.oracle.truffle.r.test.builtins.TestBuiltin_range.testNaRmAndFiniteWithLogical#Ignored.ReferenceError# #range(c(T, F, NA, NA, T), finite=T) [1] NA NA @@ -51177,130 +51356,138 @@ logical(0) Levels: A B C D ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#rep_len(1L, 4L) -[1] 1 1 1 1 - -##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len("RepeatTest", 5) } +#rep_len('RepeatTest', 5) [1] "RepeatTest" "RepeatTest" "RepeatTest" "RepeatTest" "RepeatTest" ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(1, 2) } +#rep_len(1, 2) [1] 1 1 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(1:4, 10) } +#rep_len(1:4, 10) [1] 1 2 3 4 1 2 3 4 1 2 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(1:4, 3) } +#rep_len(1:4, 3) [1] 1 2 3 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(1:4, 4) } +#rep_len(1:4, 4) [1] 1 2 3 4 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(2+6i, 4) } +#rep_len(1L, 4L) +[1] 1 1 1 1 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# +#rep_len(2+6i, 4) [1] 2+6i 2+6i 2+6i 2+6i ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(3.14159, 3) } +#rep_len(3.14159, 3) [1] 3.14159 3.14159 3.14159 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(7, "7") } +#rep_len(4, x='text') +[1] "text" "text" "text" "text" + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# +#rep_len(7, '7') [1] 7 7 7 7 7 7 7 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(7, NA) } +#rep_len(7, NA) Error in rep_len(7, NA) : invalid 'length.out' value ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(7, NULL) } +#rep_len(7, NULL) Error in rep_len(7, NULL) : invalid 'length.out' value ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(7, c(7, 42)) } +#rep_len(7, c(7, 42)) Error in rep_len(7, c(7, 42)) : invalid 'length.out' value ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(7, integer()) } +#rep_len(7, integer()) Error in rep_len(7, integer()) : invalid 'length.out' value ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(TRUE, 2) } +#rep_len(TRUE, 2) [1] TRUE TRUE ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(c(2i+3, 4+2i), 4) } -[1] 3+2i 4+2i 3+2i 4+2i +#rep_len(c('abcd', 'efg'), 0) +character(0) ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ rep_len(c(3.1415, 0.8), 1) } -[1] 3.1415 - -##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#Output.IgnoreErrorContext# -#{ rep_len(function() 42, 7) } -Error in rep_len(function() 42, 7) : attempt to replicate non-vector +#rep_len(c('abcd', 'efg'), 1) +[1] "abcd" ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ x<-as.raw(16); rep_len(x, 2) } -[1] 10 10 +#rep_len(c('abcd', 'efg'), 14) + [1] "abcd" "efg" "abcd" "efg" "abcd" "efg" "abcd" "efg" "abcd" "efg" +[11] "abcd" "efg" "abcd" "efg" ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{ x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5) } -[1] 10 05 10 05 10 +#rep_len(c('abcd', 'efg'), 2) +[1] "abcd" "efg" ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(4, x="text")} -[1] "text" "text" "text" "text" +#rep_len(c('abcd', 'efg'), 7) +[1] "abcd" "efg" "abcd" "efg" "abcd" "efg" "abcd" ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(c("abcd", "efg"), 0)} -character(0) +#rep_len(c('abcd', 'efg'), 8) +[1] "abcd" "efg" "abcd" "efg" "abcd" "efg" "abcd" "efg" ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(c("abcd", "efg"), 1)} -[1] "abcd" +#rep_len(c(2i+3, 4+2i), 4) +[1] 3+2i 4+2i 3+2i 4+2i ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(c("abcd", "efg"), 14)} - [1] "abcd" "efg" "abcd" "efg" "abcd" "efg" "abcd" "efg" "abcd" "efg" -[11] "abcd" "efg" "abcd" "efg" +#rep_len(c(3.1415, 0.8), 1) +[1] 3.1415 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(c("abcd", "efg"), 2)} -[1] "abcd" "efg" +#rep_len(c(a=1,b=4), 4) +[1] 1 4 1 4 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(c("abcd", "efg"), 7)} -[1] "abcd" "efg" "abcd" "efg" "abcd" "efg" "abcd" +#rep_len(expression(1,4,'foo'), 7) +expression(1, 4, "foo", 1, 4, "foo", 1) -##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(c("abcd", "efg"), 8)} -[1] "abcd" "efg" "abcd" "efg" "abcd" "efg" "abcd" "efg" +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen#Output.IgnoreErrorContext# +#rep_len(function() 42, 7) +Error in rep_len(function() 42, 7) : attempt to replicate non-vector ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(length.out=4, "text")} +#rep_len(length.out=4, 'text') [1] "text" "text" "text" "text" ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(length.out=4, x=1:2)} +#rep_len(length.out=4, x=1:2) [1] 1 2 1 2 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{rep_len(x=1:2, length.out=4)} +#rep_len(x=1:2, length.out=4) [1] 1 2 1 2 ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{x<-"text"; length.out<-4; rep_len(length.out=length.out, x=x)} +#x<-'text'; length.out<-4; rep_len(length.out=length.out, x=x) [1] "text" "text" "text" "text" ##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# -#{x<-"text"; length.out<-4; rep_len(x=x, length.out=length.out)} +#x<-'text'; length.out<-4; rep_len(x=x, length.out=length.out) [1] "text" "text" "text" "text" +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# +#x<-as.raw(16); rep_len(x, 2) +[1] 10 10 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_rep_len.testRepLen# +#x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5) +[1] 10 05 10 05 10 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_repint.testRepInt# #{ rep.int("a",3) } [1] "a" "a" "a" @@ -51868,7 +52055,7 @@ Error: a matrix-like object is required as argument to 'row' #{ rowMeans(matrix(as.complex(1:6), nrow=2)) } [1] 3+0i 4+0i -##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#Ignored.OutputFormatting# +##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans# #{rowMeans(matrix(NA,NA,NA),TRUE)} Error in matrix(NA, NA, NA) : invalid 'nrow' value (too large or NA) @@ -51912,11 +52099,11 @@ Error in matrix(NA, NA, NA) : invalid 'nrow' value (too large or NA) #{rowMeans(matrix(c(NA,NaN,NaN,NA),ncol=2,nrow=2))} [1] NA NaN -##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#WhiteList.arithmetic# +##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans# #{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = FALSE)} [1] NaN+0.0i 4.5+7.5i -##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans#WhiteList.arithmetic# +##com.oracle.truffle.r.test.builtins.TestBuiltin_rowMeans.testRowMeans# #{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = TRUE)} [1] 2.0+0.0i 4.5+7.5i @@ -71936,7 +72123,7 @@ In sum(argv[[1]]) : integer overflow - use sum(as.numeric(.)) Min. 1st Qu. Median Mean 3rd Qu. Max. 1.601 1.605 1.609 1.609 1.612 1.616 -##com.oracle.truffle.r.test.builtins.TestBuiltin_summary.testsummary1#Ignored.OutputFormatting# +##com.oracle.truffle.r.test.builtins.TestBuiltin_summary.testsummary1# #argv <- structure(list(object = structure(c(4L, 4L, 4L, 4L, 4L, 3L, 4L, 4L, 4L, 4L, 3L, 4L, 3L, 4L, 4L, 4L, 4L, 2L, 4L, 3L, 4L, 4L, 4L, 2L), .Dim = c(6L, 4L), .Dimnames = structure(list(c('25-34', '35-44', '45-54', '55-64', '65-74', '75+'), c('0-39g/day', '40-79', '80-119', '120+')), .Names = c('', '')), class = 'table')), .Names = 'object');do.call('summary', argv) Number of cases in table: 88 Number of factors: 2 @@ -83595,7 +83782,7 @@ Error in as.raw(1:3) %*% 1:3 : [,1] [1,] NaN -##com.oracle.truffle.r.test.library.base.TestSimpleArithmetic.testMatricesProduct#Ignored.Unknown# +##com.oracle.truffle.r.test.library.base.TestSimpleArithmetic.testMatricesProduct# #{ c(1,2,NaN,NA) %*% c(1,3,3,4) } [,1] [1,] NA @@ -85075,7 +85262,7 @@ logical(0) #{ x<-c(1,2,3);x+TRUE } [1] 2 3 4 -##com.oracle.truffle.r.test.library.base.TestSimpleArithmetic.testVectorsComplex#WhiteList.arithmetic# +##com.oracle.truffle.r.test.library.base.TestSimpleArithmetic.testVectorsComplex# #x <- c(NaN, 3+2i); xre <- Re(x); xim <- (0+1i) * Im(x); xre + xim [1] NaN+0i 3+2i @@ -166856,7 +167043,7 @@ Error: the first argument must be of mode character [,1] [,2] [2,] 2 4 -##com.oracle.truffle.r.test.library.utils.TestUtils.testMethods#Ignored.ImplementationError# +##com.oracle.truffle.r.test.library.utils.TestUtils.testMethods# #methods(plot) [1] plot.HoltWinters* plot.TukeyHSD* plot.acf* [4] plot.data.frame* plot.decomposed.ts* plot.default diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java index faeee96e0600fc36d72a1047bf8a240945ff9999..a428859a1547f0893ad37faac5c647c59bc9717e 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_anyNA.java @@ -38,7 +38,18 @@ public class TestBuiltin_anyNA extends TestBase { assertEval("anyNA(c(1, NA, 3), recursive = TRUE)"); assertEval("anyNA(list(a = c(1, 2, 3), b = 'a'))"); assertEval("anyNA(list(a = c(1, NA, 3), b = 'a'))"); + assertEval("anyNA(list(a = c('asdf', NA), b = 'a'))"); + assertEval("anyNA(list(a = c(NA, 3), b = 'a'))"); + assertEval("anyNA(list(a = NA, b = 'a'))"); + assertEval("anyNA(list(a = NA))"); + assertEval("anyNA(list(1, NA))"); + assertEval("anyNA(list(a = c('asdf', NA), b = 'a'), recursive = TRUE)"); + assertEval("anyNA(list(a = c(NA, 3), b = 'a'), recursive = TRUE)"); + assertEval("anyNA(list(a = NA, b = 'a'), recursive = TRUE)"); + assertEval("anyNA(list(a = NA), recursive = TRUE)"); + assertEval("anyNA(list(1, NA), recursive = TRUE)"); assertEval("anyNA(list(a = c(1, 2, 3), b = 'a'), recursive = TRUE)"); assertEval("anyNA(list(a = c(1, NA, 3), b = 'a'), recursive = TRUE)"); + assertEval("anyNA(list(a = c(1, 2, 3), b = list(NA, 'a')), recursive = TRUE)"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attributesassign.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attributesassign.java index 1b6a07daec94d0ce39da1d6c7278d3da07a44deb..3da11be7a2f0ebc185db7a324e438f4158edc955 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attributesassign.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_attributesassign.java @@ -53,5 +53,6 @@ public class TestBuiltin_attributesassign extends TestBase { public void testArgsCasts() { assertEval("x <- 42; attributes(x) <- 44"); assertEval("x <- 42; attributes(x) <- NULL"); + assertEval("x <- 42; attributes(x) <- list()"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java index 5b22103fc953e6e333c6a485183a380fdcde63d7..7dd4697df4814f8358a53ecbcb52206a1756bd5a 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_c.java @@ -86,12 +86,8 @@ public class TestBuiltin_c extends TestBase { @Test public void testc14() { - // FIXME FastR does not honor setting options(digits=ndecimaldigits) - // First test is a simplified problem on which the second test would fail too (besides that - // it should work fine) assertEval("options(digits=4);c(0.12345678912345,0.123)"); - assertEval(Ignored.OutputFormatting, - "argv <- list(`Grand mean` = structure(103.87323943662, class = 'mtable'), structure(list(N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('N', 'V:N')));c(argv[[1]],argv[[2]]);"); + assertEval("argv <- list(`Grand mean` = structure(103.87323943662, class = 'mtable'), structure(list(N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('N', 'V:N')));c(argv[[1]],argv[[2]]);"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_encodeString.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_encodeString.java index 29a4623970125f5ee95b1fd6c2a7ebcf21e9d8a9..332eb05d144e7cba6890d4f3ff3ec5ec810c3b5d 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_encodeString.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_encodeString.java @@ -39,8 +39,7 @@ public class TestBuiltin_encodeString extends TestBase { @Test public void testencodeString7() { - // FIXME No \b and \n encoding done in FastR - assertEval(Ignored.ImplementationError, "argv <- list('ab\\bc\\ndef', 0L, '', 0L, TRUE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))"); + assertEval("argv <- list('ab\\bc\\ndef', 0L, '', 0L, TRUE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))"); } @Test @@ -55,9 +54,7 @@ public class TestBuiltin_encodeString extends TestBase { @Test public void testencodeString10() { - // FIXME No \ to \\ encoding done - assertEval(Ignored.ImplementationError, - "argv <- list('\\\'class\\\' is a reserved slot name and cannot be redefined', 0L, '\\\'', 0L, FALSE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))"); + assertEval("argv <- list('\\\'class\\\' is a reserved slot name and cannot be redefined', 0L, '\\\'', 0L, FALSE); .Internal(encodeString(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]]))"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_iconv.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_iconv.java index 9bb79a5737fe67f7dd476bf9b6253da18a1fe47f..2f835d1662a72087ddf0588bf61708b844b29641 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_iconv.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_iconv.java @@ -24,10 +24,7 @@ public class TestBuiltin_iconv extends TestBase { @Test public void testiconv2() { - // FIXME ç is not an ASCII char (although it's an extended ASCII char wit code==135) - // and NA_character_ replacement leads to whole output to become NA - assertEval(Ignored.ImplementationError, - "argv <- list('façile' , 'latin1', 'ASCII', NA_character_, TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))"); + assertEval("argv <- list('façile' , 'latin1', 'ASCII', NA_character_, TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))"); } @Test @@ -55,9 +52,7 @@ public class TestBuiltin_iconv extends TestBase { @Test public void testiconv7() { - // FIXME ç is not an ASCII char (although it's an extended ASCII char wit code==135) - // so GnuR elimination of ç character is correct. - assertEval(Ignored.ImplementationError, "argv <- list('façile' , 'latin1', 'ASCII', '', TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))"); + assertEval("argv <- list('façile' , 'latin1', 'ASCII', '', TRUE, FALSE); .Internal(iconv(argv[[1]], argv[[2]], argv[[3]], argv[[4]], argv[[5]], argv[[6]]))"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java index c5fd6055e22beaaed6ce3435a407ee714c0c02fa..ecb854a29ac5e63c7d73d1ea071155f655d4ab3c 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_identical.java @@ -256,11 +256,8 @@ public class TestBuiltin_identical extends TestBase { // functions - // GnuR adds a srcref attribute, FastR does not, so we really can't do any comparative - // tests. - assertEval(Ignored.ImplementationError, "{ f1 <- function() {}; f2 <- function() {}; identical(f1, f2) }"); - assertEval(Ignored.ImplementationError, "{ identical(function() 42, function() 42) }"); - + assertEval("{ f1 <- function() {}; f2 <- function() {}; identical(f1, f2) }"); + assertEval("{ identical(function() 42, function() 42) }"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java index 9087339f297cad5b996b7a51b28b870a1a8cc221..7b5ffe64deb8b49683d103d3d20bccf3a60bdb27 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_list.java @@ -187,8 +187,7 @@ public class TestBuiltin_list extends TestBase { @Test public void testlist33() { - assertEval(Ignored.OutputFormatting, - "argv <- list(tables = structure(list(`Grand mean` = 103.87323943662, N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('Grand mean', 'N', 'V:N')), n = structure(list(N = structure(c(17, 18, 18, 18), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N')), `V:N` = structure(c(6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')))), .Names = c('N', 'V:N')));list(argv[[1]],argv[[2]]);"); + assertEval("argv <- list(tables = structure(list(`Grand mean` = 103.87323943662, N = structure(c(78.7365206866197, 98.5088731171753, 113.842206450509, 123.008873117175), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), class = 'mtable'), `V:N` = structure(c(79.5323303457107, 86.1989970123773, 69.7732394366197, 98.0323303457106, 108.032330345711, 89.1989970123773, 114.198997012377, 116.698997012377, 110.365663679044, 124.365663679044, 126.365663679044, 118.032330345711), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')), class = 'mtable')), .Names = c('Grand mean', 'N', 'V:N')), n = structure(list(N = structure(c(17, 18, 18, 18), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N')), `V:N` = structure(c(6, 6, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6), .Dim = 3:4, .Dimnames = structure(list(V = c('Golden.rain', 'Marvellous', 'Victory'), N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = c('V', 'N')))), .Names = c('N', 'V:N')));list(argv[[1]],argv[[2]]);"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_mean.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_mean.java index e0eb250d0b058e83e9325a6a904ddeb3e76b8272..450cfba4a7e0720977f648d9cb9ffe00ea3def90 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_mean.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_mean.java @@ -24,11 +24,7 @@ public class TestBuiltin_mean extends TestBase { @Test public void testmean2() { - // FIXME NA is returned by GnuR for NA input - // Expected output: [1] NA - // FastR output: [1] NaN - - assertEval(Ignored.ImplementationError, "argv <- list(c(0.104166666666667, 0.285714285714286, 0.285714285714286, NA)); .Internal(mean(argv[[1]]))"); + assertEval("argv <- list(c(0.104166666666667, 0.285714285714286, 0.285714285714286, NA)); .Internal(mean(argv[[1]]))"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java index 81dafef3a6aa80aa8da0ddbd86aaca31f810d4ee..d5454e3d33b83845c5902346709a439527322809 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_operators.java @@ -223,11 +223,7 @@ public class TestBuiltin_operators extends TestBase { @Test public void testoperators39() { - // FIXME number of digits in output: - // GnuR: 79.38889 98.88889 114.22222 123.38889 - // FastR: 79.3889 98.8889 114.2222 123.3889 - assertEval(Ignored.OutputFormatting, - "argv <- list(structure(c(-24.5833333333333, -5.08333333333333, 10.25, 19.4166666666667), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), strata = structure('Within', .Names = 'N'), class = 'mtable'), structure(103.972222222222, class = 'mtable'));`+`(argv[[1]],argv[[2]]);"); + assertEval("argv <- list(structure(c(-24.5833333333333, -5.08333333333333, 10.25, 19.4166666666667), .Dim = 4L, .Dimnames = structure(list(N = c('0.0cwt', '0.2cwt', '0.4cwt', '0.6cwt')), .Names = 'N'), strata = structure('Within', .Names = 'N'), class = 'mtable'), structure(103.972222222222, class = 'mtable'));`+`(argv[[1]],argv[[2]]);"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java index 42a9f0ef49eb81f41d325bbc09fcefceac17ba45..387c17b835001191ea2a0c0ac737ea68aecb02c2 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_prod.java @@ -72,36 +72,13 @@ public class TestBuiltin_prod extends TestBase { assertEval("argv <- list(numeric(0));prod(argv[[1]]);"); } + private static final String[] VALUES = {"FALSE", "TRUE", "1,FALSE", "2,TRUE", "c(2,4)", "c(2,4,3)", "c(2,4,NA)", "c(NA,2L,4L)", "1", "4L", "NA_integer_", "NA,c(1,2,3)", "c(1,2,NA),NA", "1,2,3,4", + "1L,NA,5+3i", "4+0i,6,NA", "numeric(),numeric()", "numeric()", "complex(),numeric()"}; + private static final String[] OPTIONS = {"", ",na.rm=TRUE", ",na.rm=FALSE"}; + @Test public void testProd() { - assertEval("{prod(c(2,4))}"); - assertEval("{prod(c(2,4,3))}"); - assertEval("{prod(c(1,2,3,4,5))}"); - assertEval("{prod(c(1+2i))}"); - assertEval("{prod(c(1+2i, 2+3i))}"); - assertEval("{prod(c(1+2i,1+3i,1+45i))}"); - assertEval("{prod(c(TRUE, TRUE))}"); - assertEval("{prod(c(TRUE, FALSE))}"); - assertEval("{prod()}"); - assertEval("{prod(NULL)}"); - assertEval("{prod(c())}"); - assertEval("{prod(c(),c())}"); - assertEval("{prod(2+3i,c())}"); - assertEval("{prod(2+3i,42+5i)}"); - assertEval("{prod(2+3i,42)}"); - assertEval("{prod(42,2+3i)}"); - assertEval("{prod('a')}"); - assertEval("{prod(list())}"); - assertEval("prod()"); - assertEval("prod(numeric())"); - assertEval("prod(complex())"); + assertEval(template("prod(%0%1)", VALUES, OPTIONS)); assertEval("{ foo <- function(...) prod(...); foo(); }"); } - - @Test - public void testProdNa() { - assertEval("{prod(c(2,4,NA))}"); - assertEval("{prod(c(2,4,3,NA),TRUE)}"); - assertEval("{prod(c(1,2,3,4,5,NA),FALSE)}"); - } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java index a59ce3191e6d2f43d2de2af1a03be19b9cd09be0..ba33e425f1e16bf35c7a72b5e27b8a409b239a4c 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_range.java @@ -175,7 +175,10 @@ public class TestBuiltin_range extends TestBase { @Test public void testNaRmAndFiniteWithLogical() { - assertEval(template("range(c(T, F, NA, NA, T)%0)", OPTIONAL_ARGS)); + assertEval("range(c(T, F, NA, NA, T))"); + assertEval("range(c(T, F, NA, NA, T), na.rm=T)"); + // GNU R doesn't honor "finite implies na.rm" for logical + assertEval(Ignored.ReferenceError, "range(c(T, F, NA, NA, T), finite=T)"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java index 40ff969ca503f15168ab7c4249af8a2dcf3e4c33..d41b15d4fbd2c0bc8656090556a171e46fab49aa 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rep_len.java @@ -20,41 +20,43 @@ public class TestBuiltin_rep_len extends TestBase { @Test public void testRepLen() { - assertEval("{ rep_len(1, 2) }"); - assertEval("{ rep_len(3.14159, 3) }"); - assertEval("{ rep_len(\"RepeatTest\", 5) }"); - assertEval("{ rep_len(2+6i, 4) }"); - assertEval("{ rep_len(TRUE, 2) }"); - assertEval("{ x<-as.raw(16); rep_len(x, 2) }"); - - assertEval("{ rep_len(1:4, 10) }"); - assertEval("{ rep_len(1:4, 3) }"); - assertEval("{ rep_len(1:4, 4) }"); - assertEval("{ rep_len(c(3.1415, 0.8), 1) }"); - assertEval("{ rep_len(c(2i+3, 4+2i), 4) }"); - assertEval("{ x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5) }"); + assertEval("rep_len(1, 2)"); + assertEval("rep_len(3.14159, 3)"); + assertEval("rep_len('RepeatTest', 5)"); + assertEval("rep_len(2+6i, 4)"); + assertEval("rep_len(TRUE, 2)"); + assertEval("x<-as.raw(16); rep_len(x, 2)"); + + assertEval("rep_len(1:4, 10)"); + assertEval("rep_len(1:4, 3)"); + assertEval("rep_len(1:4, 4)"); + assertEval("rep_len(c(3.1415, 0.8), 1)"); + assertEval("rep_len(c(2i+3, 4+2i), 4)"); + assertEval("x<-as.raw(16); y<-as.raw(5); rep_len(c(x, y), 5)"); // cases with named arguments: - assertEval("{rep_len(x=1:2, length.out=4)}"); - assertEval("{rep_len(length.out=4, x=1:2)}"); - assertEval("{rep_len(length.out=4, \"text\")}"); - assertEval("{rep_len(4, x=\"text\")}"); - assertEval("{x<-\"text\"; length.out<-4; rep_len(x=x, length.out=length.out)}"); - assertEval("{x<-\"text\"; length.out<-4; rep_len(length.out=length.out, x=x)}"); + assertEval("rep_len(x=1:2, length.out=4)"); + assertEval("rep_len(length.out=4, x=1:2)"); + assertEval("rep_len(length.out=4, 'text')"); + assertEval("rep_len(4, x='text')"); + assertEval("x<-'text'; length.out<-4; rep_len(x=x, length.out=length.out)"); + assertEval("x<-'text'; length.out<-4; rep_len(length.out=length.out, x=x)"); // test string vector argument - assertEval("{rep_len(c(\"abcd\", \"efg\"), 7)}"); - assertEval("{rep_len(c(\"abcd\", \"efg\"), 14)}"); - assertEval("{rep_len(c(\"abcd\", \"efg\"), 8)}"); - assertEval("{rep_len(c(\"abcd\", \"efg\"), 0)}"); - assertEval("{rep_len(c(\"abcd\", \"efg\"), 1)}"); - assertEval("{rep_len(c(\"abcd\", \"efg\"), 2)}"); - - assertEval(Output.IgnoreErrorContext, "{ rep_len(function() 42, 7) }"); - assertEval("{ rep_len(7, \"7\") }"); - assertEval("{ rep_len(7, integer()) }"); - assertEval("{ rep_len(7, NA) }"); - assertEval("{ rep_len(7, NULL) }"); - assertEval("{ rep_len(7, c(7, 42)) }"); + assertEval("rep_len(c('abcd', 'efg'), 7)"); + assertEval("rep_len(c('abcd', 'efg'), 14)"); + assertEval("rep_len(c('abcd', 'efg'), 8)"); + assertEval("rep_len(c('abcd', 'efg'), 0)"); + assertEval("rep_len(c('abcd', 'efg'), 1)"); + assertEval("rep_len(c('abcd', 'efg'), 2)"); + + assertEval(Output.IgnoreErrorContext, "rep_len(function() 42, 7)"); + assertEval("rep_len(7, '7')"); + assertEval("rep_len(7, integer())"); + assertEval("rep_len(7, NA)"); + assertEval("rep_len(7, NULL)"); + assertEval("rep_len(7, c(7, 42))"); assertEval("rep_len(1L, 4L)"); + assertEval("rep_len(c(a=1,b=4), 4)"); + assertEval("rep_len(expression(1,4,'foo'), 7)"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowMeans.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowMeans.java index d5c271e0c13ed4803940b4b100f82be141e3a978..b441e70b3f599494d4689fe2d0cad6d3cb9ae12b 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowMeans.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_rowMeans.java @@ -12,7 +12,6 @@ package com.oracle.truffle.r.test.builtins; import org.junit.Test; -import com.oracle.truffle.r.test.ArithmeticWhiteList; import com.oracle.truffle.r.test.TestBase; // Checkstyle: stop line length check @@ -55,15 +54,13 @@ public class TestBuiltin_rowMeans extends TestBase { assertEval("{rowMeans(matrix(c(TRUE,FALSE,FALSE,NA),nrow=2,ncol=2), na.rm = TRUE)}"); assertEval("{rowMeans(matrix(c(TRUE,FALSE,FALSE,NaN),nrow=2,ncol=2), na.rm = FALSE)}"); assertEval("{rowMeans(matrix(c(TRUE,FALSE,FALSE,NA),nrow=2,ncol=2), na.rm = FALSE)}"); - assertEval(ArithmeticWhiteList.WHITELIST, "{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = TRUE)}"); + assertEval("{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = TRUE)}"); + // Whichever value(NA or NaN) is first in the row will be returned for that row. assertEval("{rowMeans(matrix(c(NA,NaN,NaN,NA),ncol=2,nrow=2))}"); assertEval("{x<-matrix(c(\"1\",\"2\",\"3\",\"4\"),ncol=2);rowMeans(x)}"); - assertEval(ArithmeticWhiteList.WHITELIST, "{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = FALSE)}"); - // FIXME GnuR error description slightly better for matrix() - // Expected output: Error in matrix(NA, NA, NA) : invalid 'nrow' value (too large or NA) - // FastR output: Error: the dims contain missing values - assertEval(Ignored.OutputFormatting, "{rowMeans(matrix(NA,NA,NA),TRUE)}"); + assertEval("{rowMeans(matrix(c(NaN,4+5i,2+0i,5+10i),nrow=2,ncol=2), na.rm = FALSE)}"); + assertEval("{rowMeans(matrix(NA,NA,NA),TRUE)}"); } } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_summary.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_summary.java index 4005ecd53c17e83c5bade73b380d933bb474080d..8523b9af8cd6fedf523dba2a9cbdd8c67da1f8aa 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_summary.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_summary.java @@ -20,10 +20,8 @@ public class TestBuiltin_summary extends TestBase { @Test public void testsummary1() { - // Little rounding difference 1.4189 vs. 1.419 in FastR - assertEval(Ignored.OutputFormatting, - "argv <- structure(list(object = structure(c(4L, 4L, 4L, 4L, 4L, 3L, 4L, 4L, 4L, 4L, 3L, 4L, 3L, 4L, 4L, 4L, 4L, 2L, 4L, 3L, 4L, 4L, 4L, 2L), .Dim = c(6L, 4L), .Dimnames = structure(list(c('25-34', '35-44', '45-54', '55-64', '65-74', '75+'), c('0-39g/day', '40-79', '80-119', '120+')), .Names = c('', '')), class = 'table')), .Names = 'object');" + - "do.call('summary', argv)"); + assertEval("argv <- structure(list(object = structure(c(4L, 4L, 4L, 4L, 4L, 3L, 4L, 4L, 4L, 4L, 3L, 4L, 3L, 4L, 4L, 4L, 4L, 2L, 4L, 3L, 4L, 4L, 4L, 2L), .Dim = c(6L, 4L), .Dimnames = structure(list(c('25-34', '35-44', '45-54', '55-64', '65-74', '75+'), c('0-39g/day', '40-79', '80-119', '120+')), .Names = c('', '')), class = 'table')), .Names = 'object');" + + "do.call('summary', argv)"); } @Test diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java index 4919034187e6c12ae1efef5f0256c975047665a3..be6e824235926015ff454a9860433841958c6413 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/base/TestSimpleArithmetic.java @@ -306,7 +306,7 @@ public class TestSimpleArithmetic extends TestBase { public void testVectorsComplex() { assertEval("{ 1:4+c(1,2+2i) }"); assertEval("{ c(1,2+2i)+1:4 }"); - assertEval(ArithmeticWhiteList.WHITELIST, "x <- c(NaN, 3+2i); xre <- Re(x); xim <- (0+1i) * Im(x); xre + xim"); + assertEval("x <- c(NaN, 3+2i); xre <- Re(x); xim <- (0+1i) * Im(x); xre + xim"); } @Test @@ -475,7 +475,7 @@ public class TestSimpleArithmetic extends TestBase { assertEval("{ options(matprod = 'blas'); matrix(c(NaN,1,7,2,4,NA), nrow=3) %*% matrix(c(3,1,NA,2,NaN,5,6,7), nrow=2) }"); // NaN vs. NA issue assertEval(Ignored.Unknown, "{ c(1,2,NA,NaN) %*% c(1,3,3,4) }"); - assertEval(Ignored.Unknown, "{ c(1,2,NaN,NA) %*% c(1,3,3,4) }"); + assertEval("{ c(1,2,NaN,NA) %*% c(1,3,3,4) }"); assertEval(Ignored.Unknown, "{ c(1,2,2,3) %*% c(1,3,NA,NaN) }"); assertEval("{ c(1,2,2,3) %*% c(1,3,NaN,NA) }"); } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestUtils.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestUtils.java index 9153421fab121f4303dbb47072995541e188e8bd..5c9cd054bab285c1c5f10deafb462aad5ce8d13a 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestUtils.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/utils/TestUtils.java @@ -41,8 +41,7 @@ public class TestUtils extends TestBase { @Test public void testMethods() { - // The vector of methods is not sorted alphabetically - assertEval(Ignored.ImplementationError, "methods(plot)"); + assertEval("methods(plot)"); } private static final String[] TEST_OCTSIZE_PARAMS = {"1L", "1.0", Integer.toString(Integer.MAX_VALUE), "NA", "NULL"}; diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides index 7676e3a4aa78314400a28ca79fc7e0cb5628b01d..768ff8b911ffa742dbf5b52e356063cc315be8b1 100644 --- a/mx.fastr/copyrights/overrides +++ b/mx.fastr/copyrights/overrides @@ -195,6 +195,7 @@ com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/LoadMethod.jav com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/objects/NewObject.java,gnu_r_gentleman_ihaka.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/InheritsNode.java,purdue.copyright com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/IsFactorNode.java,purdue.copyright +com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/SizeToOctalRawNode.java,gnu_r.core.copyright com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g,purdue.copyright com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypedValue.java,gnu_r_gentleman_ihaka.copyright com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/DLL.java,gnu_r.copyright