From d9279cb54f457877deb57af3dad227a637c917c5 Mon Sep 17 00:00:00 2001 From: Adam Welc <adam.welc@oracle.com> Date: Thu, 17 Dec 2015 17:33:25 -0800 Subject: [PATCH] Added support for checking if lists, S4 objects and external pointers are identical. --- .../r/nodes/builtin/base/BasePackage.java | 2 +- .../r/nodes/builtin/base/Identical.java | 144 +++++++++++++++--- .../test/builtins/TestBuiltin_identical.java | 8 + 3 files changed, 135 insertions(+), 19 deletions(-) diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index c64c7dc9de..0650d59a1b 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -283,7 +283,7 @@ public class BasePackage extends RBuiltinPackage { add(HiddenInternalFunctions.RefCountInfo.class, HiddenInternalFunctionsFactory.RefCountInfoNodeGen::create); add(HiddenInternalFunctions.Identity.class, HiddenInternalFunctionsFactory.IdentityNodeGen::create); add(IConv.class, IConvNodeGen::create); - add(Identical.class, IdenticalNodeGen::create); + add(Identical.class, Identical::create); add(Im.class, ImNodeGen::create); add(InfixEmulationFunctions.AccessArraySubscriptBuiltin.class, InfixEmulationFunctionsFactory.AccessArraySubscriptBuiltinNodeGen::create); add(InfixEmulationFunctions.AccessArraySubscriptDefaultBuiltin.class, InfixEmulationFunctionsFactory.AccessArraySubscriptBuiltinNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java index 37c9a35b0c..78bdc41293 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Identical.java @@ -24,13 +24,18 @@ package com.oracle.truffle.r.nodes.builtin.base; import static com.oracle.truffle.r.runtime.RBuiltinKind.*; +import java.util.Iterator; + +import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.utilities.*; import com.oracle.truffle.r.nodes.builtin.*; import com.oracle.truffle.r.runtime.*; import com.oracle.truffle.r.runtime.data.*; +import com.oracle.truffle.r.runtime.data.RAttributes.RAttribute; import com.oracle.truffle.r.runtime.data.model.*; import com.oracle.truffle.r.runtime.env.*; +import com.oracle.truffle.r.runtime.nodes.RNode; import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; /** @@ -46,34 +51,59 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; @RBuiltin(name = "identical", kind = INTERNAL, parameterNames = {"x", "y", "num.eq", "single.NA", "attrib.as.set", "ignore.bytecode", "ignore.environment"}) public abstract class Identical extends RBuiltinNode { + protected abstract byte executeByte(Object x, Object y, Object numEq, Object singleNA, Object attribAsSet, Object ignoreBytecode, Object ignoreEnvironment); + + @Child private Identical identicalRecursive; + private final boolean recursive; + + public Identical(boolean recursive) { + this.recursive = recursive; + } + private final ConditionProfile vecLengthProfile = ConditionProfile.createBinaryProfile(); private final ConditionProfile naArgsProfile = ConditionProfile.createBinaryProfile(); + private byte identicalRecursive(Object x, Object y, Object numEq, Object singleNA, Object attribAsSet, Object ignoreBytecode, Object ignoreEnvironment) { + if (identicalRecursive == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + identicalRecursive = insert(IdenticalNodeGen.create(true, new RNode[7], null, null)); + } + return identicalRecursive.executeByte(x, y, numEq, singleNA, attribAsSet, ignoreBytecode, ignoreEnvironment); + } + @SuppressWarnings("unused") @Specialization(guards = "isRNull(x) || isRNull(y)") protected byte doInternalIdentical(Object x, Object y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return x == y ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(byte x, byte y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return x == y ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(String x, String y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return x.equals(y) ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(double x, double y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } boolean truth = numEq == RRuntime.LOGICAL_TRUE ? x == y : Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y); return truth ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; } @@ -81,21 +111,27 @@ public abstract class Identical extends RBuiltinNode { @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(RAbstractLogicalVector x, REnvironment y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return RRuntime.LOGICAL_FALSE; } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(REnvironment x, RAbstractLogicalVector y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return RRuntime.LOGICAL_FALSE; } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(REnvironment x, REnvironment y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } // reference equality for environments return x == y ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; } @@ -103,13 +139,17 @@ public abstract class Identical extends RBuiltinNode { @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(RSymbol x, RSymbol y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return x.getName().equals(y.getName()) ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; } @Specialization protected byte doInternalIdentical(RLanguage x, RLanguage y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } if (naArgsProfile.profile(checkExtraArgsForNA(numEq, singleNA, attribAsSet, ignoreBytecode, ignoreEnvironment))) { if (x == y) { return RRuntime.LOGICAL_TRUE; @@ -124,14 +164,18 @@ public abstract class Identical extends RBuiltinNode { @SuppressWarnings("unused") @Specialization byte doInternalIdentical(RFunction x, RFunction y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return RRuntime.asLogical(x == y); } @SuppressWarnings("unused") @Specialization(guards = "!vectorsLists(x, y)") protected byte doInternalIdenticalGeneric(RAbstractVector x, RAbstractVector y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } if (vecLengthProfile.profile(x.getLength() != y.getLength())) { return RRuntime.LOGICAL_FALSE; } else { @@ -147,41 +191,101 @@ public abstract class Identical extends RBuiltinNode { @SuppressWarnings("unused") @Specialization protected byte doInternalIdenticalGeneric(RList x, RList y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); - throw RError.nyi(this, "lists not supported in 'identical'"); + if (!recursive) { + controlVisibility(); + } + if (x.getLength() != y.getLength()) { + return RRuntime.LOGICAL_FALSE; + } + for (int i = 0; i < x.getLength(); i++) { + byte res = identicalRecursive(x.getDataAt(i), y.getDataAt(i), numEq, singleNA, attribAsSet, ignoreBytecode, ignoreEnvironment); + if (res == RRuntime.LOGICAL_FALSE) { + return RRuntime.LOGICAL_FALSE; + } + } + return RRuntime.LOGICAL_TRUE; } @Specialization protected byte doInternalIdenticalGeneric(RDataFrame x, RDataFrame y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return doInternalIdenticalGeneric(x.getVector(), y.getVector(), numEq, singleNA, attribAsSet, ignoreBytecode, ignoreEnvironment); } @SuppressWarnings("unused") @Specialization protected byte doInternalIdenticalGeneric(RFunction x, RAbstractContainer y, Object numEq, Object singleNA, Object attribAsSet, Object ignoreBytecode, Object ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return RRuntime.LOGICAL_FALSE; } @SuppressWarnings("unused") @Specialization protected byte doInternalIdenticalGeneric(RLanguage x, RAbstractContainer y, Object numEq, Object singleNA, Object attribAsSet, Object ignoreBytecode, Object ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return RRuntime.LOGICAL_FALSE; } @SuppressWarnings("unused") @Specialization protected byte doInternalIdenticalGeneric(RAbstractContainer x, RFunction y, Object numEq, Object singleNA, Object attribAsSet, Object ignoreBytecode, Object ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } return RRuntime.LOGICAL_FALSE; } + @SuppressWarnings("unused") + @Specialization + protected byte doInternalIdenticalGeneric(RS4Object x, RS4Object y, Object numEq, Object singleNA, Object attribAsSet, Object ignoreBytecode, Object ignoreEnvironment) { + if (!recursive) { + controlVisibility(); + } + if (x.isS4() != y.isS4()) { + return RRuntime.LOGICAL_FALSE; + } + RAttributes xAttributes = x.getAttributes(); + RAttributes yAttributes = y.getAttributes(); + if (xAttributes.size() == yAttributes.size()) { + Iterator<RAttribute> xIter = xAttributes.iterator(); + Iterator<RAttribute> yIter = yAttributes.iterator(); + while (xIter.hasNext()) { + RAttribute xAttr = xIter.next(); + RAttribute yAttr = yIter.next(); + if (!xAttr.getName().equals(yAttr.getName())) { + return RRuntime.LOGICAL_FALSE; + } + byte res = identicalRecursive(xAttr.getValue(), yAttr.getValue(), numEq, singleNA, attribAsSet, ignoreBytecode, ignoreEnvironment); + if (res == RRuntime.LOGICAL_FALSE) { + return RRuntime.LOGICAL_FALSE; + } + } + return RRuntime.LOGICAL_TRUE; + } + return RRuntime.LOGICAL_FALSE; + } + + @SuppressWarnings("unused") + @Specialization + protected byte doInternalIdenticalGeneric(RExternalPtr x, RExternalPtr y, Object numEq, Object singleNA, Object attribAsSet, Object ignoreBytecode, Object ignoreEnvironment) { + if (!recursive) { + controlVisibility(); + } + return RRuntime.asLogical(x.getAddr() == y.getAddr()); + } + @SuppressWarnings("unused") @Fallback protected byte doInternalIdenticalWrongTypes(Object x, Object y, byte numEq, byte singleNA, byte attribAsSet, byte ignoreBytecode, byte ignoreEnvironment) { - controlVisibility(); + if (!recursive) { + controlVisibility(); + } if (x.getClass() != y.getClass()) { return RRuntime.LOGICAL_FALSE; } else { @@ -205,4 +309,8 @@ public abstract class Identical extends RBuiltinNode { return true; } + public static Identical create(RNode[] arguments, RBuiltinFactory builtin, ArgumentsSignature suppliedSignature) { + return IdenticalNodeGen.create(false, arguments, builtin, suppliedSignature); + } + } 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 0a1ea03709..654e098a51 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 @@ -222,5 +222,13 @@ public class TestBuiltin_identical extends TestBase { assertEval("{ identical(quote(if(x) 42), quote(if(x) 7)) }"); assertEval("{ identical(quote(if(x) 42), quote(if(x) 42)) }"); assertEval("{ identical(function() 42, function() 42) }"); + + assertEval("{ setClass(\"foo\", representation(j=\"numeric\")); x<-new(\"foo\", j=42); y<-new(\"foo\", j=42); identical(x,y) }"); + assertEval("{ setClass(\"foo\", representation(j=\"numeric\")); x<-new(\"foo\", j=42); y<-new(\"foo\", j=7); identical(x,y) }"); + + assertEval("{ x<-list(7); y<-list(7); identical(x,y) }"); + assertEval("{ x<-list(7); y<-list(42); identical(x,y) }"); + assertEval("{ x<-list(list(7)); y<-list(list(7)); identical(x,y) }"); + assertEval("{ x<-list(list(7)); y<-list(list(42)); identical(x,y) }"); } } -- GitLab