diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java index 5d7b28af3fc1da1739ffc3456b7c816402c4f288..24672b60829f63b8fb5df40c2f7e5c3d7aa16526 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/BinaryBooleanScalarNode.java @@ -29,9 +29,7 @@ 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.nodes.Node; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.binary.BinaryBooleanScalarNodeGen.LogicalScalarCastNodeGen; @@ -90,7 +88,7 @@ public abstract class BinaryBooleanScalarNode extends RBuiltinNode.Arg2 { return left; } - @ImportStatic({ForeignArray2R.class, Message.class}) + @ImportStatic({RRuntime.class}) protected abstract static class LogicalScalarCastNode extends RBaseNode { protected static final int CACHE_LIMIT = 3; @@ -153,13 +151,15 @@ public abstract class BinaryBooleanScalarNode extends RBuiltinNode.Arg2 { return null; } - @Specialization(guards = {"isForeignVector(operand, hasSize)"}) + @Specialization(guards = {"isForeignObject(operand)"}) protected byte doForeignVector(TruffleObject operand, - @Cached("HAS_SIZE.createNode()") @SuppressWarnings("unused") Node hasSize, @Cached("create()") ForeignArray2R foreignArray2R, @Cached("createRecursive()") LogicalScalarCastNode recursive) { - Object o = foreignArray2R.convert(operand); - return recursive.executeCast(o); + if (foreignArray2R.isForeignVector(operand)) { + Object o = foreignArray2R.convert(operand); + return recursive.executeCast(o); + } + return doFallback(operand); } protected LogicalScalarCastNode createRecursive() { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java index 144f9715275a59198d1cb573a887ef75bcf9c106..167ed9506e76ef6839dfa0abf0c3bcd159c7fdc3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/binary/CastTypeNode.java @@ -13,8 +13,12 @@ package com.oracle.truffle.r.nodes.binary; 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.dsl.TypeSystemReference; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.nodes.unary.CastComplexNodeGen; import com.oracle.truffle.r.nodes.unary.CastDoubleNodeGen; import com.oracle.truffle.r.nodes.unary.CastIntegerNodeGen; @@ -28,9 +32,11 @@ import com.oracle.truffle.r.nodes.unary.TypeofNodeGen; import com.oracle.truffle.r.runtime.RType; import com.oracle.truffle.r.runtime.data.RTypes; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import com.oracle.truffle.r.runtime.interop.ForeignArray2R; import com.oracle.truffle.r.runtime.nodes.RBaseNode; @TypeSystemReference(RTypes.class) +@ImportStatic({ForeignArray2R.class, Message.class}) public abstract class CastTypeNode extends RBaseNode { protected static final int NUMBER_OF_TYPES = RType.values().length; @@ -61,6 +67,17 @@ public abstract class CastTypeNode extends RBaseNode { return null; } + @SuppressWarnings("unused") + @Specialization(guards = {"isForeignVector(value, hasSize)", "typeof.execute(value) != type", + "type == cachedType", "!isNull(cast)"}, limit = "NUMBER_OF_TYPES") + protected static Object doCast(TruffleObject value, RType type, + @Cached("type") RType cachedType, + @Cached("createCast(cachedType)") CastNode cast, + @Cached("HAS_SIZE.createNode()") Node hasSize, + @Cached("create()") ForeignArray2R foreignArray2R) { + return cast.doCast(foreignArray2R.convert(value)); + } + @TruffleBoundary public static CastNode createCast(RType type) { return createCast(type, false, false, false, false); diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/CastForeignNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/CastForeignNode.java index ffdfab68ea918cbe80bf88469a394ffd12e36050..e19e652678ef3909ff9129e9dec30b32fc186e1f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/CastForeignNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/builtin/casts/CastForeignNode.java @@ -23,30 +23,27 @@ package com.oracle.truffle.r.nodes.builtin.casts; 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.Message; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.nodes.unary.CastNode; import com.oracle.truffle.r.runtime.interop.ForeignArray2R; -@ImportStatic({ForeignArray2R.class, Message.class}) +@ImportStatic({ForeignArray2R.class}) public abstract class CastForeignNode extends CastNode { protected CastForeignNode() { } - @Specialization(guards = {"isForeignVector(obj, hasSize)"}) + @Specialization(guards = {"foreignArray2R.isForeignVector(obj)"}) protected Object castForeign(TruffleObject obj, - @Cached("HAS_SIZE.createNode()") @SuppressWarnings("unused") Node hasSize, @Cached("create()") ForeignArray2R foreignArray2R) { return foreignArray2R.convert(obj); } - @Fallback - protected Object passThrough(Object x) { - return x; + @Specialization(guards = {"!foreignArray2R.isForeignVector(obj)"}) + protected Object passThrough(Object obj, + @Cached("create()") ForeignArray2R foreignArray2R) { + return obj; } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/GetNonSharedNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/GetNonSharedNode.java index 9e70abd64665b293003018354688c1fc2cbe9285..db740ca48618cb897780231a7e813f32b7007cb3 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/GetNonSharedNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/GetNonSharedNode.java @@ -61,11 +61,16 @@ public abstract class GetNonSharedNode extends Node { } @Specialization(guards = "shareable.getClass() == shareableClass") - protected RTypedValue getNonShared(RSharingAttributeStorage shareable, + protected RTypedValue getNonSharedCached(RSharingAttributeStorage shareable, @Cached("shareable.getClass()") Class<? extends RSharingAttributeStorage> shareableClass) { return shareableClass.cast(shareable).getNonShared(); } + @Specialization(replaces = "getNonSharedCached") + protected RTypedValue getNonShared(RSharingAttributeStorage shareable) { + return shareable.getNonShared(); + } + @Fallback protected Object getNonShared(Object o) { RSharingAttributeStorage.verify(o); 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 bb0ee89090157db4a9aa1b38e2e6145d16efea89..4f2f375192eb681092cf8f87eef33ad04c367e80 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 @@ -28,9 +28,7 @@ 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.Message; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.control.RLengthNode; @@ -60,7 +58,7 @@ import com.oracle.truffle.r.runtime.ops.na.NACheck; * (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. */ -@ImportStatic({ForeignArray2R.class, Message.class, RRuntime.class}) +@ImportStatic({RRuntime.class}) @TypeSystemReference(RTypes.class) public abstract class UnaryArithmeticReduceNode extends RBaseNode { @@ -376,13 +374,15 @@ public abstract class UnaryArithmeticReduceNode extends RBaseNode { return handleString(operand, naRm, finite, 0); } - @Specialization(guards = {"isForeignVector(obj, hasSize)"}) + @Specialization(guards = {"isForeignObject(obj)"}) protected Object doForeignVector(TruffleObject obj, boolean naRm, boolean finite, - @Cached("HAS_SIZE.createNode()") @SuppressWarnings("unused") Node hasSize, @Cached("create()") ForeignArray2R foreignArray2R, @Cached("createRecursive()") UnaryArithmeticReduceNode recursive) { - Object vec = foreignArray2R.convert(obj); - return recursive.executeReduce(vec, naRm, finite); + if (foreignArray2R.isForeignVector(obj)) { + Object vec = foreignArray2R.convert(obj); + return recursive.executeReduce(vec, naRm, finite); + } + return doFallback(obj, naRm, finite); } @Fallback 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 37f5bbd40577900255b8c0621df9436f424fe470..acd72feaf1484c0c8e4a36165d7538c523617628 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,9 +32,7 @@ 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.nodes.Node; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; @@ -55,7 +53,7 @@ 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({ForeignArray2R.class, Message.class}) +@ImportStatic({RRuntime.class}) @RBuiltin(name = "!", kind = PRIMITIVE, parameterNames = {""}, dispatch = OPS_GROUP_GENERIC, behavior = PURE_ARITHMETIC) public abstract class UnaryNotNode extends RBuiltinNode.Arg1 { @@ -219,13 +217,15 @@ public abstract class UnaryNotNode extends RBuiltinNode.Arg1 { return RDataFactory.createEmptyLogicalVector(); } - @Specialization(guards = {"isForeignVector(obj, hasSize)"}) + @Specialization(guards = {"isForeignObject(obj)"}) protected Object doForeign(VirtualFrame frame, TruffleObject obj, - @Cached("HAS_SIZE.createNode()") @SuppressWarnings("unused") Node hasSize, @Cached("create()") ForeignArray2R foreignArray2R, @Cached("createRecursive()") UnaryNotNode recursive) { - Object vec = foreignArray2R.convert(obj); - return recursive.execute(frame, vec); + if (foreignArray2R.isForeignVector(obj)) { + Object vec = foreignArray2R.convert(obj); + return recursive.execute(frame, vec); + } + return invalidArgType(obj); } protected UnaryNotNode createRecursive() { 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 e9380c9401879609108663d3c69cd1a083a183d3..bb59cfc10cae05de573a6806be5509dc8c48a24c 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 @@ -360,7 +360,7 @@ public abstract class ForeignArray2R extends RBaseNode { return RRuntime.isForeignObject(obj) && ForeignAccess.sendHasSize(hasSize, (TruffleObject) obj); } - protected boolean isForeignVector(Object obj) { + public boolean isForeignVector(Object obj) { return isJavaIterable(obj) || isForeignArray(obj, hasSize); } 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 8bd5b6e68b9563df6f49186b63f669d347e3d5a5..a427b2e44237e58209a85f48549e645fc59e6d1f 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 @@ -142382,6 +142382,35 @@ NULL #if (!any(R.version$engine == "FastR")) { as.character(list()) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));as.character(to$listEmpty); } character(0) +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testElseIf# +#if (!any(R.version$engine == "FastR")) { c(1,1,1) } else { ta <- new('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestArraysClass'); ifelse(ta$integerArray, 1, 2) } +[1] 1 1 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testElseIf# +#if (!any(R.version$engine == "FastR")) { c(1,1,1) } else { ta <- new('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestArraysClass'); ifelse(ta$integerList, 1, 2) } +[1] 1 1 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testElseIf# +#if (!any(R.version$engine == "FastR")) { c(1,2,1) } else { ta <- new('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestArraysClass'); ifelse(ta$booleanArray, 1, 2) } +[1] 1 2 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testElseIf# +#if (!any(R.version$engine == "FastR")) { c(1,2,1) } else { ta <- new('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestArraysClass'); ifelse(ta$booleanList, 1, 2) } +[1] 1 2 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testElseIf# +#if (!any(R.version$engine == "FastR")) { c(NA, NA, NA) } else { ta <- new('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestArraysClass'); ifelse(ta$stringArray, 1, 2) } +[1] NA NA NA + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testElseIf# +#if (!any(R.version$engine == "FastR")) { c(NA, NA, NA) } else { ta <- new('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestArraysClass'); ifelse(ta$stringList, 1, 2) } +[1] NA NA NA + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testElseIf# +#if (!any(R.version$engine == "FastR")) { cat('Error in as.logical(test) :', '<<<NEWLINE>>>', ' no method for coercing this external object to a vector', '<<<NEWLINE>>>') } else { ta <- new('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestArraysClass'); ifelse(ta) } +Error in as.logical(test) : + no method for coercing this external object to a vector + ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# #if (!any(R.version$engine == "FastR")) { "a string" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); to$fieldStaticStringObject } [1] "a string" diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java index be1cf379799e363f55dc5535dc2c570676c7a42f..ad80239ab65b27287f05fd591b93272cae55e0a4 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java @@ -1102,6 +1102,17 @@ public class TestJavaInterop extends TestBase { assertEvalFastR(CREATE_TRUFFLE_OBJECT + "for(i in to$listInteger) print(i)", "for(i in c(1,2,3)) print(i)"); } + @Test + public void testElseIf() throws IllegalArgumentException { + assertEvalFastR(CREATE_TEST_ARRAYS + " ifelse(ta)", errorIn("as.logical(test)", "no method for coercing this external object to a vector")); + assertEvalFastR(CREATE_TEST_ARRAYS + " ifelse(ta$booleanArray, 1, 2)", "c(1,2,1)"); + assertEvalFastR(CREATE_TEST_ARRAYS + " ifelse(ta$booleanList, 1, 2)", "c(1,2,1)"); + assertEvalFastR(CREATE_TEST_ARRAYS + " ifelse(ta$integerArray, 1, 2)", "c(1,1,1)"); + assertEvalFastR(CREATE_TEST_ARRAYS + " ifelse(ta$integerList, 1, 2)", "c(1,1,1)"); + assertEvalFastR(CREATE_TEST_ARRAYS + " ifelse(ta$stringArray, 1, 2)", "c(NA, NA, NA)"); + assertEvalFastR(CREATE_TEST_ARRAYS + " ifelse(ta$stringList, 1, 2)", "c(NA, NA, NA)"); + } + @Test public void testForeignVectorArithmeticOp() throws NoSuchFieldException, IllegalAccessException {