diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java index 0977298652e9af68fe7ab8bd7a591b384d8c388f..2677032f64c39371eead62102ce392dbc3b817fd 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/IsFiniteFunctions.java @@ -30,18 +30,12 @@ import java.util.Arrays; import java.util.function.DoublePredicate; import java.util.function.IntPredicate; -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 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.attributes.SpecialAttributesFunctions.InitDimsNamesDimNamesNode; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.nodes.unary.TypeofNode; import com.oracle.truffle.r.runtime.RError; @@ -49,7 +43,6 @@ 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.RList; import com.oracle.truffle.r.runtime.data.RLogicalVector; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; @@ -65,12 +58,7 @@ public class IsFiniteFunctions { @ImportStatic(RRuntime.class) public abstract static class Adapter extends RBuiltinNode.Arg1 { - @Child private GetDimAttributeNode getDims = GetDimAttributeNode.create(); - @Child private GetNamesAttributeNode getNames = GetNamesAttributeNode.create(); - @Child private GetDimNamesAttributeNode getDimNames = GetDimNamesAttributeNode.create(); - @Child private SetDimNamesAttributeNode setDimNames; - - @CompilationFinal private ConditionProfile setDimNamesProfile; + @Child private InitDimsNamesDimNamesNode initDimsNamesDimNames = InitDimsNamesDimNamesNode.create(); @FunctionalInterface protected interface ComplexPredicate { @@ -112,7 +100,9 @@ public class IsFiniteFunctions { protected RLogicalVector doFunConstant(RAbstractVector x, byte value) { byte[] b = new byte[x.getLength()]; Arrays.fill(b, value); - return transferDimNames(RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR, getDims.getDimensions(x), getNames.getNames(x)), x); + RLogicalVector result = RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR); + initDimsNamesDimNames.initAttributes(result, x); + return result; } protected RLogicalVector doFunDouble(RAbstractDoubleVector x, DoublePredicate fun) { @@ -120,7 +110,9 @@ public class IsFiniteFunctions { for (int i = 0; i < b.length; i++) { b[i] = RRuntime.asLogical(fun.test(x.getDataAt(i))); } - return transferDimNames(RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR, getDims.getDimensions(x), getNames.getNames(x)), x); + RLogicalVector result = RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR); + initDimsNamesDimNames.initAttributes(result, x); + return result; } protected RLogicalVector doFunLogical(RAbstractLogicalVector x, LogicalPredicate fun) { @@ -128,7 +120,9 @@ public class IsFiniteFunctions { for (int i = 0; i < b.length; i++) { b[i] = RRuntime.asLogical(fun.test(x.getDataAt(i))); } - return transferDimNames(RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR, getDims.getDimensions(x), getNames.getNames(x)), x); + RLogicalVector result = RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR); + initDimsNamesDimNames.initAttributes(result, x); + return result; } protected RLogicalVector doFunInt(RAbstractIntVector x, IntPredicate fun) { @@ -136,7 +130,9 @@ public class IsFiniteFunctions { for (int i = 0; i < b.length; i++) { b[i] = RRuntime.asLogical(fun.test(x.getDataAt(i))); } - return transferDimNames(RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR, getDims.getDimensions(x), getNames.getNames(x)), x); + RLogicalVector result = RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR); + initDimsNamesDimNames.initAttributes(result, x); + return result; } protected RLogicalVector doFunComplex(RAbstractComplexVector x, ComplexPredicate fun) { @@ -144,21 +140,8 @@ public class IsFiniteFunctions { for (int i = 0; i < b.length; i++) { b[i] = RRuntime.asLogical(fun.test(x.getDataAt(i))); } - return transferDimNames(RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR, getDims.getDimensions(x), getNames.getNames(x)), x); - } - - RLogicalVector transferDimNames(RLogicalVector result, RAbstractVector src) { - RList dimNames = getDimNames.getDimNames(src); - if (setDimNamesProfile == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - setDimNamesProfile = ConditionProfile.createBinaryProfile(); - } - if (setDimNamesProfile.profile(dimNames != null)) { - if (setDimNames == null) { - setDimNames = insert(SetDimNamesAttributeNode.create()); - } - setDimNames.setDimNames(result, dimNames); - } + RLogicalVector result = RDataFactory.createLogicalVector(b, RDataFactory.COMPLETE_VECTOR); + initDimsNamesDimNames.initAttributes(result, x); return result; } } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java index 09bde8d617b02030f4f908522f51447acb1d3173..59ba9f961eea560aaadd527e6d8eec5084f4b67b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/LogFunctions.java @@ -37,8 +37,7 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.attributes.CopyOfRegAttributesNode; -import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetDimAttributeNode; -import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.GetNamesAttributeNode; +import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctions.InitDimsNamesDimNamesNode; import com.oracle.truffle.r.nodes.binary.BinaryMapArithmeticFunctionNode; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; @@ -165,24 +164,22 @@ public class LogFunctions { @Cached("createClassProfile()") ValueProfile vectorProfile, @Cached("createBinaryProfile()") ConditionProfile isNAProfile, @Cached("create()") CopyOfRegAttributesNode copyAttrsNode, - @Cached("create()") GetNamesAttributeNode getNamesNode, - @Cached("create()") GetDimAttributeNode getDimsNode, + @Cached("create()") InitDimsNamesDimNamesNode initDimsNamesDimNames, @Cached("create()") NACheck xNACheck, @Cached("create()") NACheck baseNACheck) { RAbstractDoubleVector doubleVector = (RAbstractDoubleVector) vectorProfile.profile(vector).castSafe(RType.Double, isNAProfile); - return logInternal(doubleVector, base, copyAttrsNode, getNamesNode, getDimsNode, xNACheck, baseNACheck); + return logInternal(doubleVector, base, copyAttrsNode, initDimsNamesDimNames, xNACheck, baseNACheck); } @Specialization protected RComplexVector log(RAbstractComplexVector vector, double base, @Cached("createClassProfile()") ValueProfile vectorProfile, @Cached("create()") CopyOfRegAttributesNode copyAttrsNode, - @Cached("create()") GetNamesAttributeNode getNamesNode, - @Cached("create()") GetDimAttributeNode getDimsNode, + @Cached("create()") InitDimsNamesDimNamesNode initDimsNamesDimNames, @Cached("createDivNode()") BinaryMapArithmeticFunctionNode divNode, @Cached("create()") NACheck xNACheck, @Cached("create()") NACheck baseNACheck) { - return logInternal(vectorProfile.profile(vector), RComplex.valueOf(base, 0), divNode, getDimsNode, getNamesNode, copyAttrsNode, xNACheck, baseNACheck); + return logInternal(vectorProfile.profile(vector), RComplex.valueOf(base, 0), divNode, initDimsNamesDimNames, copyAttrsNode, xNACheck, baseNACheck); } @Specialization @@ -190,16 +187,15 @@ public class LogFunctions { @Cached("createClassProfile()") ValueProfile vectorProfile, @Cached("createBinaryProfile()") ConditionProfile isNAProfile, @Cached("create()") CopyOfRegAttributesNode copyAttrsNode, - @Cached("create()") GetNamesAttributeNode getNamesNode, - @Cached("create()") GetDimAttributeNode getDimsNode, + @Cached("create()") InitDimsNamesDimNamesNode initDimsNamesDimNames, @Cached("createDivNode()") BinaryMapArithmeticFunctionNode divNode, @Cached("create()") NACheck xNACheck, @Cached("create()") NACheck baseNACheck) { RAbstractComplexVector complexVector = (RAbstractComplexVector) vectorProfile.profile(vector).castSafe(RType.Complex, isNAProfile); - return logInternal(complexVector, base, divNode, getDimsNode, getNamesNode, copyAttrsNode, xNACheck, baseNACheck); + return logInternal(complexVector, base, divNode, initDimsNamesDimNames, copyAttrsNode, xNACheck, baseNACheck); } - private RDoubleVector logInternal(RAbstractDoubleVector vector, double base, CopyOfRegAttributesNode copyAttrsNode, GetNamesAttributeNode getNamesNode, GetDimAttributeNode getDimsNode, + private RDoubleVector logInternal(RAbstractDoubleVector vector, double base, CopyOfRegAttributesNode copyAttrsNode, InitDimsNamesDimNamesNode initDimsNamesDimNames, NACheck xNACheck, NACheck baseNACheck) { baseNACheck.enable(base); double[] resultVector = new double[vector.getLength()]; @@ -220,7 +216,7 @@ public class LogFunctions { } } boolean complete = xNACheck.neverSeenNA() && baseNACheck.neverSeenNA(); - return createResult(vector, resultVector, complete, copyAttrsNode, getNamesNode, getDimsNode); + return createResult(vector, resultVector, complete, copyAttrsNode, initDimsNamesDimNames); } private double logb(double x, double base, NAProfile naBase) { @@ -258,8 +254,8 @@ public class LogFunctions { return result; } - private RComplexVector logInternal(RAbstractComplexVector vector, RComplex base, BinaryMapArithmeticFunctionNode divNode, GetDimAttributeNode getDimsNode, GetNamesAttributeNode getNamesNode, - CopyOfRegAttributesNode copyAttrsNode, NACheck xNACheck, NACheck baseNACheck) { + private RComplexVector logInternal(RAbstractComplexVector vector, RComplex base, BinaryMapArithmeticFunctionNode divNode, + InitDimsNamesDimNamesNode initDimsNamesDimNames, CopyOfRegAttributesNode copyAttrsNode, NACheck xNACheck, NACheck baseNACheck) { baseNACheck.enable(base); double[] complexVector = new double[vector.getLength() * 2]; if (baseNACheck.check(base)) { @@ -285,7 +281,7 @@ public class LogFunctions { } } boolean complete = xNACheck.neverSeenNA() && baseNACheck.neverSeenNA(); - return createResult(vector, complexVector, complete, getDimsNode, getNamesNode, copyAttrsNode); + return createResult(vector, complexVector, complete, initDimsNamesDimNames, copyAttrsNode); } private static void fill(double[] array, int i, RComplex rc) { @@ -328,16 +324,18 @@ public class LogFunctions { return RComplex.valueOf(Math.log(mod), arg); } - private static RDoubleVector createResult(RAbstractVector source, double[] resultData, boolean complete, CopyOfRegAttributesNode copyAttrsNode, GetNamesAttributeNode getNamesNode, - GetDimAttributeNode getDimsNode) { - RDoubleVector result = RDataFactory.createDoubleVector(resultData, complete, getDimsNode.getDimensions(source), getNamesNode.getNames(source)); + private static RDoubleVector createResult(RAbstractVector source, double[] resultData, boolean complete, + CopyOfRegAttributesNode copyAttrsNode, InitDimsNamesDimNamesNode initDimsNamesDimNames) { + RDoubleVector result = RDataFactory.createDoubleVector(resultData, complete); + initDimsNamesDimNames.initAttributes(result, source); copyAttrsNode.execute(source, result); return result; } - private static RComplexVector createResult(RAbstractVector source, double[] resultData, boolean complete, GetDimAttributeNode getDimsNode, GetNamesAttributeNode getNamesNode, - CopyOfRegAttributesNode copyAttrsNode) { - RComplexVector result = RDataFactory.createComplexVector(resultData, complete, getDimsNode.getDimensions(source), getNamesNode.getNames(source)); + private static RComplexVector createResult(RAbstractVector source, double[] resultData, boolean complete, + InitDimsNamesDimNamesNode initDimsNamesDimNames, CopyOfRegAttributesNode copyAttrsNode) { + RComplexVector result = RDataFactory.createComplexVector(resultData, complete); + initDimsNamesDimNames.initAttributes(result, source); copyAttrsNode.execute(source, result); return result; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java index 30896b1446fccb004ddfc74b1a6964a6637fbf8a..aa5ab4daaf5c8e4ea9176bbdeaaf1fbdddedceca 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/attributes/SpecialAttributesFunctions.java @@ -31,6 +31,7 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.LoopConditionProfile; import com.oracle.truffle.api.profiles.ValueProfile; +import com.oracle.truffle.r.nodes.access.vector.ExtractListElement; import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.GetDimAttributeNodeGen; import com.oracle.truffle.r.nodes.function.opt.ShareObjectNode; import com.oracle.truffle.r.runtime.RError; @@ -439,16 +440,17 @@ public final class SpecialAttributesFunctions { @Cached("createClassProfile()") ValueProfile xTypeProfile, @Cached("create()") BranchProfile namesNullProfile, @Cached("create()") BranchProfile dimNamesAvlProfile, - @Cached("create()") GetDimNamesAttributeNode getDimNames) { + @Cached("create()") GetDimNamesAttributeNode getDimNames, + @Cached("create()") ExtractListElement extractListElement) { RStringVector names = (RStringVector) super.getAttrFromAttributable(x, attrNullProfile, attrStorageProfile, xTypeProfile); if (names == null) { namesNullProfile.enter(); RList dimNames = getDimNames.getDimNames(x); if (dimNames != null && dimNames.getLength() == 1) { dimNamesAvlProfile.enter(); - Object dimName = dimNames.getDataAt(0); - return (dimName != RNull.instance) ? dimName : null; // For - // ".Dimnames=list(NULL)" + Object dimName = extractListElement.execute(dimNames, 0); + // RNull for ".Dimnames=list(NULL)" + return (dimName != RNull.instance) ? dimName : null; } return null; } @@ -878,6 +880,104 @@ public final class SpecialAttributesFunctions { } } + public abstract static class InitDimsNamesDimNamesNode extends RBaseNode { + + private final ConditionProfile oldAttrsNullProfile = ConditionProfile.createBinaryProfile(); + private final ConditionProfile doAnythingProfile = ConditionProfile.createBinaryProfile(); + + @Child private GetDimAttributeNode getDimNode; + @Child private GetNamesAttributeNode getNamesNode; + @Child private GetDimNamesAttributeNode getDimNamesNode; + + protected InitDimsNamesDimNamesNode() { + } + + public static InitDimsNamesDimNamesNode create() { + return SpecialAttributesFunctionsFactory.InitDimsNamesDimNamesNodeGen.create(); + } + + public void initAttributes(RAbstractContainer x, int[] dimensions, RStringVector names, RList dimNames) { + if (doAnythingProfile.profile(dimensions != null || names != null || dimNames != null)) { + execute(x, dimensions, names, dimNames); + } + } + + public void initAttributes(RAbstractContainer x, RAbstractContainer source) { + if (getDimNode == null) { + getDimNode = insert(GetDimAttributeNode.create()); + getNamesNode = insert(GetNamesAttributeNode.create()); + getDimNamesNode = insert(GetDimNamesAttributeNode.create()); + } + this.initAttributes(x, getDimNode.getDimensions(source), getNamesNode.getNames(source), getDimNamesNode.getDimNames(source)); + } + + public abstract void execute(RAbstractContainer x, int[] dimensions, RStringVector names, RList dimNames); + + @Specialization + protected void initContainerAttributes(RAbstractContainer x, int[] dimensions, RStringVector names, RList dimNames, + @Cached("create()") ShareObjectNode shareObjectNode) { + assert names != x; + assert dimNames != x; + DynamicObject attrs = x.getAttributes(); + if (dimNames != null) { + shareObjectNode.execute(dimNames); + } + if (names != null) { + assert names.getLength() == x.getLength() : "size mismatch: names.length=" + names.getLength() + " vs. length=" + x.getLength(); + if (dimensions != null && dimensions.length == 1) { + // one-dimensional arrays do not have names, only dimnames with one value + if (dimNames == null) { + shareObjectNode.execute(names); + dimNames = RDataFactory.createList(new Object[]{names}); + } + names = null; + } else { + shareObjectNode.execute(names); + } + } + + if (attrs == null) { + if (dimensions != null) { + RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true); + if (dimNames != null) { + attrs = RAttributesLayout.createDimAndDimNames(dimensionsVector, dimNames); + if (names != null) { + attrs.define(RRuntime.NAMES_ATTR_KEY, names); + } + } else { + if (names != null) { + attrs = RAttributesLayout.createNamesAndDim(names, dimensionsVector); + } else { + attrs = RAttributesLayout.createDim(dimensionsVector); + } + } + } else { + if (dimNames != null) { + attrs = RAttributesLayout.createDimNames(dimNames); + if (names != null) { + attrs.define(RRuntime.NAMES_ATTR_KEY, names); + } + } else { + assert (names != null); // only called with at least one attr != null + attrs = RAttributesLayout.createNames(names); + } + } + x.initAttributes(attrs); + } else { // attrs != null + if (dimensions != null) { + RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true); + x.setAttr(RRuntime.DIM_ATTR_KEY, dimensionsVector); + } + if (names != null) { + x.setAttr(RRuntime.NAMES_ATTR_KEY, names); + } + if (dimNames != null) { + x.setAttr(RRuntime.DIMNAMES_ATTR_KEY, dimNames); + } + } + } + } + public abstract static class SetRowNamesAttributeNode extends SetSpecialAttributeNode { private final ConditionProfile nullRowNamesProfile = ConditionProfile.createBinaryProfile(); 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 f8c0488a44e0c579aa393c39f7e671c8471297b4..26503bfece54f28770a35e3d24fdfa35c5995abc 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 @@ -37,20 +37,21 @@ public final class RComplexVector extends RVector<double[]> implements RAbstract private final double[] data; - RComplexVector(double[] data, boolean complete, int[] dims, RStringVector names) { - super(complete, data.length >> 1, dims, names); + RComplexVector(double[] data, boolean complete) { + super(complete); assert data.length % 2 == 0; this.data = data; assert verify(); } - private RComplexVector(double[] data, boolean complete, int[] dims) { - this(data, complete, dims, null); + RComplexVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + this(data, complete); + initDimsNamesDimNames(dims, names, dimNames); } @Override protected RComplexVector internalCopy() { - return new RComplexVector(Arrays.copyOf(data, data.length), this.isComplete(), null); + return new RComplexVector(Arrays.copyOf(data, data.length), this.isComplete()); } @Override 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 eb98e8cdd860a965330f16fb53512c3de75354cc..06f3c97902603be00b2dd49044ba68de9b30138f 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 @@ -69,7 +69,7 @@ public final class RDataFactory { } public static RIntVector createIntVector(int[] data, boolean complete) { - return createIntVector(data, complete, null, null); + return traceDataCreated(new RIntVector(data, complete)); } public static RIntVector createIntVector(int[] data, boolean complete, int[] dims) { @@ -81,7 +81,11 @@ public final class RDataFactory { } public static RIntVector createIntVector(int[] data, boolean complete, int[] dims, RStringVector names) { - return traceDataCreated(new RIntVector(data, complete, dims, names)); + return createIntVector(data, complete, dims, names, null); + } + + public static RIntVector createIntVector(int[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(new RIntVector(data, complete, dims, names, dimNames)); } public static RDoubleVector createDoubleVector(int length) { @@ -97,7 +101,7 @@ public final class RDataFactory { } public static RDoubleVector createDoubleVector(double[] data, boolean complete) { - return createDoubleVector(data, complete, null, null); + return traceDataCreated(new RDoubleVector(data, complete)); } public static RDoubleVector createDoubleVector(double[] data, boolean complete, int[] dims) { @@ -109,7 +113,11 @@ public final class RDataFactory { } public static RDoubleVector createDoubleVector(double[] data, boolean complete, int[] dims, RStringVector names) { - return traceDataCreated(new RDoubleVector(data, complete, dims, names)); + return createDoubleVector(data, complete, dims, names, null); + } + + public static RDoubleVector createDoubleVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(new RDoubleVector(data, complete, dims, names, dimNames)); } public static RRawVector createRawVector(int length) { @@ -117,7 +125,7 @@ public final class RDataFactory { } public static RRawVector createRawVector(byte[] data) { - return createRawVector(data, null, null); + return traceDataCreated(new RRawVector(data)); } public static RRawVector createRawVector(byte[] data, int[] dims) { @@ -129,7 +137,11 @@ public final class RDataFactory { } public static RRawVector createRawVector(byte[] data, int[] dims, RStringVector names) { - return traceDataCreated(new RRawVector(data, dims, names)); + return createRawVector(data, dims, names, null); + } + + public static RRawVector createRawVector(byte[] data, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(new RRawVector(data, dims, names, dimNames)); } public static RComplexVector createComplexVector(int length) { @@ -144,11 +156,11 @@ public final class RDataFactory { data[i + 1] = RRuntime.COMPLEX_NA_IMAGINARY_PART; } } - return createComplexVector(data, !fillNA, null, null); + return createComplexVector(data, !fillNA); } public static RComplexVector createComplexVector(double[] data, boolean complete) { - return createComplexVector(data, complete, null, null); + return traceDataCreated(new RComplexVector(data, complete)); } public static RComplexVector createComplexVector(double[] data, boolean complete, int[] dims) { @@ -160,11 +172,15 @@ public final class RDataFactory { } public static RComplexVector createComplexVector(double[] data, boolean complete, int[] dims, RStringVector names) { - return traceDataCreated(new RComplexVector(data, complete, dims, names)); + return createComplexVector(data, complete, dims, names, null); + } + + public static RComplexVector createComplexVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(new RComplexVector(data, complete, dims, names, dimNames)); } public static RStringVector createStringVector(String value) { - return createStringVector(new String[]{value}, !RRuntime.isNA(value), null, null); + return createStringVector(new String[]{value}, !RRuntime.isNA(value)); } public static RStringVector createStringVector(int length) { @@ -182,7 +198,7 @@ public final class RDataFactory { } public static RStringVector createStringVector(String[] data, boolean complete) { - return createStringVector(data, complete, null, null); + return traceDataCreated(new RStringVector(data, complete)); } public static RStringVector createStringVector(String[] data, boolean complete, int[] dims) { @@ -194,7 +210,11 @@ public final class RDataFactory { } public static RStringVector createStringVector(String[] data, boolean complete, int[] dims, RStringVector names) { - return traceDataCreated(new RStringVector(data, complete, dims, names)); + return createStringVector(data, complete, dims, names, null); + } + + public static RStringVector createStringVector(String[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(new RStringVector(data, complete, dims, names, dimNames)); } public static RLogicalVector createLogicalVector(int length) { @@ -206,11 +226,11 @@ public final class RDataFactory { if (fillNA) { Arrays.fill(data, RRuntime.LOGICAL_NA); } - return createLogicalVector(data, false, null, null); + return createLogicalVector(data, false); } public static RLogicalVector createLogicalVector(byte[] data, boolean complete) { - return createLogicalVector(data, complete, null, null); + return traceDataCreated(new RLogicalVector(data, complete)); } public static RLogicalVector createLogicalVector(byte[] data, boolean complete, int[] dims) { @@ -222,7 +242,11 @@ public final class RDataFactory { } public static RLogicalVector createLogicalVector(byte[] data, boolean complete, int[] dims, RStringVector names) { - return traceDataCreated(new RLogicalVector(data, complete, dims, names)); + return createLogicalVector(data, complete, dims, names, null); + } + + public static RLogicalVector createLogicalVector(byte[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + return traceDataCreated(new RLogicalVector(data, complete, dims, names, dimNames)); } public static RLogicalVector createNAVector(int length) { @@ -359,7 +383,7 @@ public final class RDataFactory { } public static RList createList(Object[] data) { - return createList(data, null, null); + return traceDataCreated(new RList(data)); } public static RComplex createComplexZero() { @@ -375,11 +399,11 @@ public final class RDataFactory { } public static RList createList() { - return createList(new Object[0], null, null); + return createList(new Object[0]); } public static RList createList(int n) { - return createList(createRNullArray(n), null, null); + return createList(createRNullArray(n)); } public static RList createList(int size, RStringVector names) { @@ -391,7 +415,11 @@ public final class RDataFactory { } public static RList createList(Object[] data, int[] newDimensions, RStringVector names) { - return traceDataCreated(new RList(data, newDimensions, names)); + return createList(data, newDimensions, names, null); + } + + public static RList createList(Object[] data, int[] newDimensions, RStringVector names, RList dimNames) { + return traceDataCreated(new RList(data, newDimensions, names, dimNames)); } public static RExpression createExpression(int size) { 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 52366b1ae86c5a4e41c6927140452ebbe52043c8..aba05f10a7db066f2269327c97f558ff8e5e7219 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 @@ -37,14 +37,15 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD private final double[] data; - RDoubleVector(double[] data, boolean complete, int[] dims, RStringVector names) { - super(complete, data.length, dims, names); + RDoubleVector(double[] data, boolean complete) { + super(complete); this.data = data; assert verify(); } - private RDoubleVector(double[] data, boolean complete, int[] dims) { - this(data, complete, dims, null); + RDoubleVector(double[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + this(data, complete); + initDimsNamesDimNames(dims, names, dimNames); } @Override @@ -67,7 +68,7 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD @Override protected RDoubleVector internalCopy() { - return new RDoubleVector(Arrays.copyOf(data, data.length), this.isComplete(), null); + return new RDoubleVector(Arrays.copyOf(data, data.length), this.isComplete()); } @Override @@ -95,7 +96,7 @@ public final class RDoubleVector extends RVector<double[]> implements RAbstractD break; } } - RDoubleVector result = new RDoubleVector(newData, isComplete, null); + RDoubleVector result = new RDoubleVector(newData, isComplete); setAttributes(result); return result; } 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 e8cbeb5a4e73d8d7f97be1fa5774fbfede93c691..2e0463d5598a60d179459766246a95f4569ab2c7 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 @@ -31,7 +31,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractVector; public final class RExpression extends RListBase implements RAbstractVector { RExpression(Object[] data, int[] dims, RStringVector names) { - super(data, dims, names); + super(data, dims, names, null); } @Override 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 d95bb428e4a28c9fed63b1a57ae8527276bf708f..face5053d948c54629159b8c5f306d61c84978cb 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 @@ -37,14 +37,15 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect private final int[] data; - RIntVector(int[] data, boolean complete, int[] dims, RStringVector names) { - super(complete, data.length, dims, names); + RIntVector(int[] data, boolean complete) { + super(complete); this.data = data; assert verify(); } - private RIntVector(int[] data, boolean complete, int[] dims) { - this(data, complete, dims, null); + RIntVector(int[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + this(data, complete); + initDimsNamesDimNames(dims, names, dimNames); } @Override @@ -89,7 +90,7 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect @Override protected RIntVector internalCopy() { - return new RIntVector(Arrays.copyOf(data, data.length), isComplete(), null); + return new RIntVector(Arrays.copyOf(data, data.length), isComplete()); } public RIntVector copyResetData(int[] newData) { @@ -100,7 +101,7 @@ public final class RIntVector extends RVector<int[]> implements RAbstractIntVect break; } } - RIntVector result = new RIntVector(newData, isComplete, null); + RIntVector result = new RIntVector(newData, isComplete); setAttributes(result); return result; } 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 4b0bb9a76b856198d26874513fa49fb2100aef33..650c2f1173a80e6c7cf1f3b8dd5c56724421af39 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 @@ -31,8 +31,12 @@ public final class RList extends RListBase implements RAbstractListVector { public String elementNamePrefix; - RList(Object[] data, int[] dims, RStringVector names) { - super(data, dims, names); + RList(Object[] data) { + super(data); + } + + RList(Object[] data, int[] dims, RStringVector names, RList dimNames) { + super(data, dims, names, dimNames); } @Override @@ -42,7 +46,7 @@ public final class RList extends RListBase implements RAbstractListVector { @Override protected RList internalCopy() { - return new RList(Arrays.copyOf(data, data.length), getDimensionsInternal(), null); + return new RList(Arrays.copyOf(data, data.length), getDimensionsInternal(), null, null); } @TruffleBoundary @@ -54,7 +58,7 @@ public final class RList extends RListBase implements RAbstractListVector { protected RList internalDeepCopy() { // TOOD: only used for nested list updates, but still could be made faster (through a // separate AST node?) - RList listCopy = new RList(Arrays.copyOf(data, data.length), getDimensionsInternal(), null); + RList listCopy = new RList(Arrays.copyOf(data, data.length), getDimensionsInternal(), null, null); for (int i = 0; i < listCopy.getLength(); i++) { Object el = listCopy.getDataAt(i); if (el instanceof RVector) { 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 4a796edb8499890e7203816ac3d434c52f90d2f7..305e605d2621b422c7365abfb63dfe30646abe25 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 @@ -50,12 +50,17 @@ public abstract class RListBase extends RVector<Object[]> implements RAbstractLi protected final Object[] data; - RListBase(Object[] data, int[] dims, RStringVector names) { - super(false, data.length, dims, names); + RListBase(Object[] data) { + super(false); this.data = data; assert verify(); } + RListBase(Object[] data, int[] dims, RStringVector names, RList dimNames) { + this(data); + initDimsNamesDimNames(dims, names, dimNames); + } + @Override public final int getLength() { return data.length; 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 3bde20df8e776d6571b91dd07dee09db4b6c2988..5f0472308588aee30a4952a3311e835a55c7d612 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 @@ -37,14 +37,15 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo private final byte[] data; - RLogicalVector(byte[] data, boolean complete, int[] dims, RStringVector names) { - super(complete, data.length, dims, names); + RLogicalVector(byte[] data, boolean complete) { + super(complete); this.data = data; assert verify(); } - private RLogicalVector(byte[] data, boolean complete, int[] dims) { - this(data, complete, dims, null); + RLogicalVector(byte[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + this(data, complete); + initDimsNamesDimNames(dims, names, dimNames); } @Override @@ -86,7 +87,7 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo @Override protected RLogicalVector internalCopy() { - return new RLogicalVector(Arrays.copyOf(data, data.length), isComplete(), null); + return new RLogicalVector(Arrays.copyOf(data, data.length), isComplete()); } public RLogicalVector copyResetData(byte[] newData) { @@ -97,7 +98,7 @@ public final class RLogicalVector extends RVector<byte[]> implements RAbstractLo break; } } - RLogicalVector result = new RLogicalVector(newData, isComplete, null); + RLogicalVector result = new RLogicalVector(newData, isComplete); setAttributes(result); return result; } 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 26252b7da5746b0efdfd06af7ed539a09ff6c070..1d680bc8bae69c9274ab42b77bf8f65557da1f14 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 @@ -37,14 +37,15 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec private final byte[] data; - RRawVector(byte[] data, int[] dims, RStringVector names) { - super(true, data.length, dims, names); + RRawVector(byte[] data) { + super(true); this.data = data; assert verify(); } - private RRawVector(byte[] data, int[] dims) { - this(data, dims, null); + RRawVector(byte[] data, int[] dims, RStringVector names, RList dimNames) { + this(data); + initDimsNamesDimNames(dims, names, dimNames); } @Override @@ -89,7 +90,7 @@ public final class RRawVector extends RVector<byte[]> implements RAbstractRawVec @Override protected RRawVector internalCopy() { - return new RRawVector(Arrays.copyOf(data, data.length), null); + return new RRawVector(Arrays.copyOf(data, data.length)); } @Override 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 38fdbb99181b237ae911db36a6074201c5ed22c3..7fb2ffdad2bb3f978fda84fe63838ba6e1095ef1 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 @@ -38,14 +38,15 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS private final String[] data; - RStringVector(String[] data, boolean complete, int[] dims, RStringVector names) { - super(complete, data.length, dims, names); + RStringVector(String[] data, boolean complete) { + super(complete); this.data = data; assert verify(); } - private RStringVector(String[] data, boolean complete, int[] dims) { - this(data, complete, dims, null); + RStringVector(String[] data, boolean complete, int[] dims, RStringVector names, RList dimNames) { + this(data, complete); + initDimsNamesDimNames(dims, names, dimNames); } @Override @@ -79,7 +80,7 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS @Override protected RStringVector internalCopy() { - return new RStringVector(Arrays.copyOf(data, data.length), isComplete(), null); + return new RStringVector(Arrays.copyOf(data, data.length), isComplete()); } @Override @@ -102,7 +103,7 @@ public final class RStringVector extends RVector<String[]> implements RAbstractS break; } } - RStringVector result = new RStringVector(newData, isComplete, null); + RStringVector result = new RStringVector(newData, isComplete); setAttributes(result); return result; } 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 5af392c0858ff416f7d37a96a11f27436e593744..ad2756524f8c0ca8b4ea1a7677fea16f55ab2c33 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 @@ -62,29 +62,8 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement protected boolean complete; // "complete" means: does not contain NAs - protected RVector(boolean complete, int length, int[] dimensions, RStringVector names) { + protected RVector(boolean complete) { this.complete = complete; - assert names != this; - if (names != null) { - // since this constructor is for internal use only, the assertion shouldn't fail - assert names.getLength() == length : "size mismatch: " + names.getLength() + " vs. " + length; - if (dimensions == null) { - initAttributes(RAttributesLayout.createNames(names)); - } else { - RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true); - if (dimensions.length != 1) { - initAttributes(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)); - } - } - } else { - if (dimensions != null) { - initAttributes(RAttributesLayout.createDim(RDataFactory.createIntVector(dimensions, true))); - } - } } private int[] getDimensionsFromAttrs() { @@ -601,6 +580,59 @@ public abstract class RVector<ArrayT> extends RSharingAttributeStorage implement this.setDimNames(vector.getDimNames(), invokingNode); } + /** + * 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) { + assert (this.attributes == null) : "Vector attributes must be null"; + assert names != this; + assert dimNames != this; + 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); + } + } 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); + } + } + 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.length != 1) { + initAttributes(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)); + } + } else { + initAttributes(RAttributesLayout.createNames(names)); + } + } else { + if (dimensions != null) { + RIntVector dimensionsVector = RDataFactory.createIntVector(dimensions, true); + initAttributes(RAttributesLayout.createDim(dimensionsVector)); + } + } + } + } + public final boolean copyNamesFrom(RAbstractVector vector) { CompilerAsserts.neverPartOfCompilation(); 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 fea2f45e62a7463bd1751d0bed3671df96e26760..5288c6fc4ac7f00ba3f6e2bf05cd1327feefb666 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 @@ -33817,6 +33817,30 @@ Error in lockEnvironment("foo", TRUE) : not an environment #{ round( log(10,2), digits = 5 ) } [1] 3.32193 +##com.oracle.truffle.r.test.builtins.TestBuiltin_log.testLogAttrs# +#{ x <- array(1:3, 1); dimnames(x) <- list('a'); r <- log(x); names(r)[[1]] <- 'new'; list(x=x, r=r); } +$x +a +1 + +$r +new + 0 + + +##com.oracle.truffle.r.test.builtins.TestBuiltin_log.testLogAttrs# +#{ x <- array(1:3, 3, list(x=c('x1','x2','x3'))); r <- log(x); r; } +x + x1 x2 x3 +0.0000000 0.6931472 1.0986123 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_log.testLogAttrs# +#{ y <- array(1:6, c(2,3), list(y=c('y1','y2'), x=c('x1','x2','x3'))); r <- log(y); r; } + x +y x1 x2 x3 + y1 0.0000000 1.098612 1.609438 + y2 0.6931472 1.386294 1.791759 + ##com.oracle.truffle.r.test.builtins.TestBuiltin_log.testLogComplex# #{ log(-10-1i, 10) } [1] 1.002161-1.321091i diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_log.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_log.java index 4e5da9071abda26fdb9bc07abc9dd67b653c1032..28cf30f87f6d259667aedad31624ebf6a68fbf22 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_log.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_log.java @@ -170,4 +170,12 @@ public class TestBuiltin_log extends TestBase { assertEval("{ log(c(0.0, 0.0), 0+0i) }"); assertEval("{ log(c(0+0i, 0+0i), 0+0i) }"); } + + @Test + public void testLogAttrs() { + assertEval("{ x <- array(1:3, 1); dimnames(x) <- list('a'); r <- log(x); names(r)[[1]] <- 'new'; list(x=x, r=r); }"); + assertEval("{ x <- array(1:3, 3, list(x=c('x1','x2','x3'))); r <- log(x); r; }"); + assertEval("{ y <- array(1:6, c(2,3), list(y=c('y1','y2'), x=c('x1','x2','x3'))); r <- log(y); r; }"); + } + }