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 1ce4dba99c396ca5e9a4bb6923dca210d8f7c020..d3871d27be24f6105aa6adb51ee81c45046fd98b 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 @@ -116,6 +116,8 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRTree; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeStats; import com.oracle.truffle.r.nodes.builtin.fastr.FastRTreeStatsNodeGen; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRTry; +import com.oracle.truffle.r.nodes.builtin.fastr.FastRTryNodeGen; import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrls; import com.oracle.truffle.r.nodes.builtin.fastr.FastrDqrlsNodeGen; import com.oracle.truffle.r.nodes.unary.UnaryNotNode; @@ -344,6 +346,7 @@ public class BasePackage extends RBuiltinPackage { add(FastrDqrls.class, FastrDqrlsNodeGen::create); add(FastRDebug.class, FastRDebugNodeGen::create); add(FastRIdentity.class, FastRIdentityNodeGen::create); + add(FastRTry.class, FastRTryNodeGen::create); add(FastRInspect.class, FastRInspectNodeGen::create); add(FastRInterop.Eval.class, FastRInteropFactory.EvalNodeGen::create); add(FastRInterop.Export.class, FastRInteropFactory.ExportNodeGen::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 d09327df33adcbcc37d12ec61d6e45381f840780..f1a329fcac628d268a1adc5fe061ed14f7e8df4c 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 @@ -111,32 +111,50 @@ public abstract class Identical extends RBuiltinNode { @SuppressWarnings("unused") @Specialization(guards = "isRNull(x) || isRNull(y)") protected byte doInternalIdenticalNull(Object x, Object y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment) { - return x == y ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; + return RRuntime.asLogical(x == y); } @SuppressWarnings("unused") @Specialization(guards = "isRMissing(x) || isRMissing(y)") protected byte doInternalIdenticalMissing(Object x, Object y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment) { - return x == y ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; + return RRuntime.asLogical(x == y); } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(byte x, byte y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment) { - return x == y ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; + return RRuntime.asLogical(x == y); } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(String x, String y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment) { - return x.equals(y) ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; + return RRuntime.asLogical(x.equals(y)); } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(double x, double y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment) { - boolean truth = numEq ? x == y : Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y); - return truth ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; + if (singleNA) { + if (RRuntime.isNA(x)) { + return RRuntime.asLogical(RRuntime.isNA(y)); + } else if (RRuntime.isNA(y)) { + return RRuntime.LOGICAL_FALSE; + } else if (Double.isNaN(x)) { + return RRuntime.asLogical(Double.isNaN(y)); + } else if (Double.isNaN(y)) { + return RRuntime.LOGICAL_FALSE; + } + } + if (numEq) { + if (!singleNA) { + if (Double.isNaN(x) || Double.isNaN(y)) { + return RRuntime.asLogical(Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y)); + } + } + return RRuntime.asLogical(x == y); + } + return RRuntime.asLogical(Double.doubleToRawLongBits(x) == Double.doubleToRawLongBits(y)); } private byte identicalAttr(RAttributable x, RAttributable y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment) { @@ -182,14 +200,14 @@ public abstract class Identical extends RBuiltinNode { @Specialization protected byte doInternalIdentical(REnvironment x, REnvironment y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment) { // reference equality for environments - return x == y ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; + return RRuntime.asLogical(x == y); } @SuppressWarnings("unused") @Specialization protected byte doInternalIdentical(RSymbol x, RSymbol y, boolean numEq, boolean singleNA, boolean attribAsSet, boolean ignoreBytecode, boolean ignoreEnvironment) { assert Utils.isInterned(x.getName()) && Utils.isInterned(y.getName()); - return x.getName() == y.getName() ? RRuntime.LOGICAL_TRUE : RRuntime.LOGICAL_FALSE; + return RRuntime.asLogical(x.getName() == y.getName()); } @Specialization diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java new file mode 100644 index 0000000000000000000000000000000000000000..071ef08d2a93304f80ef7f32d0c3661722fef431 --- /dev/null +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRTry.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016, 2016, 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.builtin.fastr; + +import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; +import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; + +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.FrameSlot; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.r.nodes.access.FrameSlotNode; +import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; +import com.oracle.truffle.r.nodes.function.RCallBaseNode; +import com.oracle.truffle.r.nodes.function.RCallNode; +import com.oracle.truffle.r.runtime.RRuntime; +import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; +import com.oracle.truffle.r.runtime.data.RFunction; + +/** + * Allows to be 100% robust even in the case of FastR errors like runtime exceptions. The argument + * must be a single parameter-less function. The return value is true on success, otherwise error + * message. + */ +@RBuiltin(name = ".fastr.try", kind = PRIMITIVE, parameterNames = {""}, behavior = COMPLEX) +public abstract class FastRTry extends RBuiltinNode { + private final Object argsIdentifier = new Object(); + @Child private RCallBaseNode call = RCallNode.createExplicitCall(argsIdentifier); + @Child private FrameSlotNode slot = FrameSlotNode.createTemp(argsIdentifier, true); + + @Specialization + public Object tryFunc(VirtualFrame frame, RFunction func) { + FrameSlot frameSlot = slot.executeFrameSlot(frame); + try { + frame.setObject(frameSlot, RArgsValuesAndNames.EMPTY); + call.execute(frame, func); + } catch (Throwable ex) { + return String.format("Exception %s, message: %s", ex.getClass().getSimpleName(), ex.getMessage()); + } finally { + frame.setObject(frameSlot, null); + } + return RRuntime.LOGICAL_TRUE; + } +} 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 091a74bf33a0039c83ba9da968ebbd63b7efaf81..0511c8d585f61a5d9907da2693d1cd95b17c2ce7 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 @@ -22205,6 +22205,70 @@ attr(,"Rd_tag") #x <- 1; y <- 1; attr(x, "f") <- 2; attr(x, "g") <- 1; attr(y, "g") <- 1; attr(y, "f") <- 2; identical(x, y) [1] TRUE +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(0/-1, NaN, num.eq=F, single.NA=F) +[1] FALSE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(0/-1, NaN, num.eq=F, single.NA=T) +[1] FALSE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(0/-1, NaN, num.eq=T, single.NA=F) +[1] FALSE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(0/-1, NaN, num.eq=T, single.NA=T) +[1] FALSE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(0/0, NaN, num.eq=F, single.NA=F) +[1] FALSE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(0/0, NaN, num.eq=F, single.NA=T) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(0/0, NaN, num.eq=T, single.NA=F) +[1] FALSE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(0/0, NaN, num.eq=T, single.NA=T) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(NA, NA, num.eq=F, single.NA=F) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(NA, NA, num.eq=F, single.NA=T) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(NA, NA, num.eq=T, single.NA=F) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(NA, NA, num.eq=T, single.NA=T) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(NaN, NaN, num.eq=F, single.NA=F) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(NaN, NaN, num.eq=F, single.NA=T) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(NaN, NaN, num.eq=T, single.NA=F) +[1] TRUE + +##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testDoubles# +#identical(NaN, NaN, num.eq=T, single.NA=T) +[1] TRUE + ##com.oracle.truffle.r.test.builtins.TestBuiltin_identical.testIdentical#Ignored.ImplementationError# #{ f1 <- function() {}; f2 <- function() {}; identical(f1, f2) } [1] FALSE 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 86e31f2ae4c3f25e469ed2ca906d821807ffb256..6811de383289d6f4fd895805930c125ee5e77f33 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 @@ -263,4 +263,13 @@ public class TestBuiltin_identical extends TestBase { assertEval(Ignored.ImplementationError, "{ identical(function() 42, function() 42) }"); } + + @Test + public void testDoubles() { + assertEval(template("identical(%0, num.eq=%1, single.NA=%2)", new String[][]{ + new String[]{"NA, NA", "NaN, NaN", "0/0, NaN", "0/-1, NaN"}, + new String[]{"T", "F"}, + new String[]{"T", "F"} + })); + } }