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 ac9d5aa0bc70311575eb482b5521b1207fb2f4fa..938bee74e62f37f18dc335788f6ada2609f2ede4 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 @@ -371,8 +371,10 @@ public class BasePackage extends RBuiltinPackage { add(FastRInterop.Export.class, FastRInteropFactory.ExportNodeGen::create); add(FastRInterop.HasSize.class, FastRInteropFactory.HasSizeNodeGen::create); add(FastRInterop.Import.class, FastRInteropFactory.ImportNodeGen::create); + add(FastRInterop.InteropNew.class, FastRInteropFactory.InteropNewNodeGen::create); add(FastRInterop.IsNull.class, FastRInteropFactory.IsNullNodeGen::create); add(FastRInterop.IsExecutable.class, FastRInteropFactory.IsExecutableNodeGen::create); + add(FastRInterop.JavaClass.class, FastRInteropFactory.JavaClassNodeGen::create); add(FastRInterop.ToBoolean.class, FastRInteropFactory.ToBooleanNodeGen::create); add(FastRRefCountInfo.class, FastRRefCountInfoNodeGen::create); add(FastRPkgSource.class, FastRPkgSourceNodeGen::create); 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 333055b1fb03ab4daf7c57182cd0935444466624..e8b5fdc22fef6506438b79306cdda20f8f1e8951 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 @@ -1360,12 +1360,10 @@ public abstract class ConnectionFunctions { ByteChannel ch = JavaInterop.asJavaObject(ByteChannel.class, channel); return new ChannelRConnection("", ch, open, encoding).asVector(); } - throw error(RError.Message.INVALID_CHANNEL_OBJECT, JavaInterop.unbox(channel).getClass()); + throw error(RError.Message.INVALID_CHANNEL_OBJECT); } catch (IOException ex) { throw RInternalError.shouldNotReachHere(); } } - } - } diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java index bb8b0830c7506c448902790900a4480c8fdd82de..cbce750d0918da1af2b72833f68f41a90336de89 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Names.java @@ -27,17 +27,27 @@ 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.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.TruffleObject; +import com.oracle.truffle.api.nodes.Node; 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.runtime.RInternalError; +import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.builtins.RBuiltin; +import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.env.REnvironment; +@ImportStatic({RRuntime.class, com.oracle.truffle.api.interop.Message.class}) @RBuiltin(name = "names", kind = PRIMITIVE, parameterNames = {"x"}, dispatch = INTERNAL_GENERIC, behavior = PURE) public abstract class Names extends RBuiltinNode { @@ -64,6 +74,35 @@ public abstract class Names extends RBuiltinNode { return env.ls(true, null, false); } + @Specialization(guards = "isForeignObject(obj)") + protected Object getNames(TruffleObject obj, + @Cached("GET_SIZE.createNode()") Node getSizeNode, + @Cached("KEYS.createNode()") Node keysNode, + @Cached("READ.createNode()") Node readNode, + @Cached("IS_BOXED.createNode()") Node isBoxedNode, + @Cached("UNBOX.createNode()") Node unboxNode) { + + try { + TruffleObject keys = (TruffleObject) ForeignAccess.send(keysNode, obj); + if (keys != null) { + int size = (Integer) ForeignAccess.sendGetSize(getSizeNode, keys); + String[] names = new String[size]; + for (int i = 0; i < size; i++) { + Object value; + value = ForeignAccess.sendRead(readNode, keys, i); + if (value instanceof TruffleObject && ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) value)) { + value = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) value); + } + names[i] = (String) value; + } + return RDataFactory.createStringVector(names, true); + } + return RNull.instance; + } catch (InteropException e) { + throw RInternalError.shouldNotReachHere(e); + } + } + @Fallback protected RNull getNames(@SuppressWarnings("unused") Object operand) { return RNull.instance; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java index 5b86993957b17f1caaee84eab20fc9d3a8471eca..25e8d6eaeb611ef3abc24680873cde862e2e4cf3 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/SeqFunctions.java @@ -15,7 +15,6 @@ import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.gte; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.missingConstant; 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.nodes.builtin.CastBuilder.Predef.numericValue; import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.size; import static com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder.newCastBuilder; import static com.oracle.truffle.r.runtime.RDispatch.INTERNAL_GENERIC; diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java index 90f93075889b3d4d08d7db5c15b0bddc1d3bf75b..fcc48d956d3e48d6b64105079cc0d80038ddc58d 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java @@ -40,9 +40,14 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.Truffle; 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.ArityException; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.TruffleObject; +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.DirectCallNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; @@ -55,9 +60,15 @@ import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.builtins.RBuiltin; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; 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.RAbstractLogicalVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractRawVector; +import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; public class FastRInterop { @@ -250,4 +261,73 @@ public class FastRInterop { return value; } } + + @RBuiltin(name = ".fastr.java.class", visibility = ON, kind = PRIMITIVE, parameterNames = {"class"}, behavior = COMPLEX) + public abstract static class JavaClass extends RBuiltinNode { + + static { + Casts casts = new Casts(JavaClass.class); + casts.arg("class").mustBe(stringValue()).asStringVector().mustBe(Predef.singleElement()).findFirst(); + } + + @Specialization + @TruffleBoundary + public TruffleObject javaClass(String clazz) { + try { + return JavaInterop.asTruffleObject(Class.forName(clazz)); + } catch (ClassNotFoundException | SecurityException | IllegalArgumentException e) { + throw error(Message.GENERIC, "error while accessing Java class: " + e.getMessage()); + } + } + } + + @ImportStatic({com.oracle.truffle.api.interop.Message.class, RRuntime.class}) + @RBuiltin(name = ".fastr.interop.new", visibility = ON, kind = PRIMITIVE, parameterNames = {"class", "..."}, behavior = COMPLEX) + public abstract static class InteropNew extends RBuiltinNode { + + static { + Casts.noCasts(InteropNew.class); + } + + private static Object toJava(Object value) { + Object vector = RRuntime.asAbstractVector(value); + if (vector instanceof RAbstractAtomicVector && ((RAbstractAtomicVector) vector).getLength() == 1) { + if (vector instanceof RAbstractDoubleVector) { + RAbstractDoubleVector v = (RAbstractDoubleVector) vector; + return v.getDataAt(0); + } else if (vector instanceof RAbstractLogicalVector) { + RAbstractLogicalVector v = (RAbstractLogicalVector) vector; + return v.getDataAt(0) == RRuntime.LOGICAL_TRUE; + } else if (vector instanceof RAbstractRawVector) { + RAbstractRawVector v = (RAbstractRawVector) vector; + return v.getDataAt(0).getValue(); + } else if (vector instanceof RAbstractStringVector) { + RAbstractStringVector v = (RAbstractStringVector) vector; + return v.getDataAt(0); + } + } + return value; + } + + @Specialization(limit = "99", guards = {"isForeignObject(clazz)", "length == args.getLength()"}) + @TruffleBoundary + public Object interopNew(TruffleObject clazz, RArgsValuesAndNames args, + @SuppressWarnings("unused") @Cached("args.getLength()") int length, + @Cached("createNew(length).createNode()") Node sendNew) { + try { + Object[] argValues = new Object[args.getLength()]; + for (int i = 0; i < argValues.length; i++) { + argValues[i] = toJava(args.getArgument(i)); + } + return ForeignAccess.sendNew(sendNew, clazz, argValues); + } catch (SecurityException | IllegalArgumentException | UnsupportedTypeException | ArityException | UnsupportedMessageException e) { + throw error(Message.GENERIC, "error during Java object instantiation: " + e.getMessage()); + } + } + + @Fallback + public Object interopNew(@SuppressWarnings("unused") Object clazz, @SuppressWarnings("unused") Object args) { + throw error(Message.GENERIC, "interop object needed as receiver of NEW message"); + } + } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java index b79bd831270de1056e75d0f899a33d6e43fcdf64..3268b3bd7628561656dd61a7cae16fc56f90d46f 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ArgumentMatcher.java @@ -60,7 +60,6 @@ import com.oracle.truffle.r.runtime.data.RPromise.PromiseState; import com.oracle.truffle.r.runtime.data.RPromise.RPromiseFactory; import com.oracle.truffle.r.runtime.nodes.RBaseNode; import com.oracle.truffle.r.runtime.nodes.RNode; -import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; /** * <p> diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java index 72ab6fa32cf256222a315ac3d2f38419ccdfc8cb..38f80bcd6a4e9651ff0e4135b632380de2cc7a48 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java @@ -855,7 +855,7 @@ public final class RError extends RuntimeException { TRUNCATE_NOT_ENABLED("truncation not enabled for this connection"), TRUNCATE_UNSUPPORTED_FOR_CONN("cannot truncate connection: %s"), INCOMPLETE_STRING_AT_EOF_DISCARDED("incomplete string at end of file has been discarded"), - INVALID_CHANNEL_OBJECT("invalid channel object type: %s"), + INVALID_CHANNEL_OBJECT("invalid channel object (ByteChannel expected)"), INVALID_TAG("invalid tag"), INVALID_VARIABLE_NAMES("invalid variable names"), INVALID_EXPRESSION("invalid expression in '%s'"), 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 82eec933b6800e081b3dc4856878d4cbe6fc274d..e0d3de69805cc1ae9818feff2efeba042e25f70e 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 @@ -30,7 +30,6 @@ import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.object.DynamicObject; -import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntime; 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 47a9ac5e75d203d2058a781d31adb8a86117b586..eca54bee2cc810c911c12e0855fdc6af835b5d44 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 @@ -129769,6 +129769,11 @@ a b c d e ##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropExport# #if (length(grep("FastR", R.Version()$version.string)) != 1) { invisible() } else { .fastr.interop.export('foo', new.env()) } +##com.oracle.truffle.r.test.library.fastr.TestInterop.testPrinting# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { c('intValue', 'longValue', 'charValue', 'shortValue', 'booleanValue', 'stringValue') } else { v <- .fastr.interop.import('testPOJO'); names(v) } +[1] "intValue" "longValue" "charValue" "shortValue" "booleanValue" +[6] "stringValue" + ##com.oracle.truffle.r.test.library.fastr.TestInterop.testPrinting# #if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('$intValue\n[1] 1\n\n$longValue\n[1] 123412341234\n\n$charValue\n[1] "R"\n\n$shortValue\n[1] -100\n\n$booleanValue\n[1] TRUE\n\n$stringValue\n[1] "foo"\n\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { v <- .fastr.interop.import('testPOJO'); print(v) } $intValue @@ -129838,22 +129843,6 @@ attr(,"is.truffle.object") #if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { { x<-rep(1, 100); xi1<-.fastr.identity(x); f<-function(x) { y<-x; y }; f(x); x[1]<-7; xi2<-.fastr.identity(x); xi1 == xi2 } } [1] TRUE -##com.oracle.truffle.r.test.library.grid.TestGridPackage.testUnits# -#{ library(grid); 3 * (unit(1, 'mm')); } -[1] 3*1mm - -##com.oracle.truffle.r.test.library.grid.TestGridPackage.testUnits# -#{ library(grid); grid:::unit.list(3 * unit(1, 'mm')); } -[1] 3*1mm - -##com.oracle.truffle.r.test.library.grid.TestGridPackage.testUnits# -#{ library(grid); unit.c(unit(1,'mm'), 42*unit(1,'mm')); } -[1] 1mm 42*1mm - -##com.oracle.truffle.r.test.library.grid.TestGridPackage.testUnits# -#{ library(grid); unit.c(unit(1,'mm'), unit(1,'mm')) } -[1] 1mm 1mm - ##com.oracle.truffle.r.test.library.methods.TestSubstituteDirect.basicTests# #a<-substituteDirect(quote(x+1), NA); a Error in substituteDirect(quote(x + 1), NA) : diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java index 2250149cb2075b762143b4d249ff3d3c5a5ddc6c..35c727bf15d4abd98cd9527133e1d26b7cee275e 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -118,5 +118,6 @@ public class TestInterop extends TestBase { assertEvalFastR("v <- .fastr.interop.import('testIntArray'); v", "cat('[1] 1 -5 199\\n" + "attr(,\"is.truffle.object\")\\n" + "[1] TRUE\\n')"); + assertEvalFastR("v <- .fastr.interop.import('testPOJO'); names(v)", "c('intValue', 'longValue', 'charValue', 'shortValue', 'booleanValue', 'stringValue')"); } }