From 6fa3afd9e63a345c67a109602c92198bf6c91a8b Mon Sep 17 00:00:00 2001 From: Tomas Stupka <tomas.stupka@oracle.com> Date: Mon, 26 Jun 2017 16:35:42 +0200 Subject: [PATCH] access foreign elements via index/name vector --- .../access/vector/ExtractVectorNode.java | 192 +++++++++++------- .../r/runtime/interop/ForeignArray2R.java | 131 +++++++----- .../truffle/r/test/ExpectedTestOutput.test | 171 ++++++++++++++++ .../r/test/library/fastr/TestJavaInterop.java | 125 ++++++++++++ 4 files changed, 492 insertions(+), 127 deletions(-) diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java index e6017cd274..d246ce5719 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ExtractVectorNode.java @@ -32,7 +32,6 @@ import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.InteropException; import com.oracle.truffle.api.interop.KeyInfo; import com.oracle.truffle.api.interop.TruffleObject; -import com.oracle.truffle.api.interop.UnknownIdentifierException; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; @@ -54,6 +53,8 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractListVector; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.interop.Foreign2RNodeGen; +import com.oracle.truffle.r.runtime.interop.ForeignArray2R; +import com.oracle.truffle.r.runtime.interop.ForeignArray2R.InteropTypeCheck; import com.oracle.truffle.r.runtime.nodes.RBaseNode; @ImportStatic({RRuntime.class, com.oracle.truffle.api.interop.Message.class}) @@ -97,7 +98,26 @@ public abstract class ExtractVectorNode extends RBaseNode { protected abstract Object execute(VirtualFrame frame, Object vector, Object[] positions, Object exact, Object dropDimensions); - protected static boolean isForeignObject(TruffleObject object) { + @Specialization(guards = {"cached != null", "cached.isSupported(vector, positions)"}) + protected Object doExtractSameDimensions(VirtualFrame frame, RAbstractVector vector, Object[] positions, Object exact, Object dropDimensions, // + @Cached("createRecursiveCache(vector, positions)") RecursiveExtractSubscriptNode cached) { + return cached.apply(frame, vector, positions, exact, dropDimensions); + } + + @Specialization(guards = {"cached != null", "cached.isSupported(vector, positions)"}) + protected Object doExtractRecursive(VirtualFrame frame, RAbstractListVector vector, Object[] positions, Object exact, Object dropDimensions, // + @Cached("createRecursiveCache(vector, positions)") RecursiveExtractSubscriptNode cached) { + return cached.apply(frame, vector, positions, exact, dropDimensions); + } + + protected RecursiveExtractSubscriptNode createRecursiveCache(Object vector, Object[] positions) { + if (isRecursiveSubscript(vector, positions)) { + return RecursiveExtractSubscriptNode.create((RAbstractListVector) vector, positions[0]); + } + return null; + } + + protected static boolean isForeignObject(Object object) { return RRuntime.isForeignObject(object); } @@ -109,7 +129,90 @@ public abstract class ExtractVectorNode extends RBaseNode { return Foreign2RNodeGen.create(); } - @Specialization(guards = {"isForeignObject(object)", "positions.length == cachedLength"}) + protected boolean positionsByVector(Object[] positions) { + return positions.length == 1 && positions[0] instanceof RAbstractVector && ((RAbstractVector) positions[0]).getLength() > 1; + } + + private boolean isRecursiveSubscript(Object vector, Object[] positions) { + return !recursive && !ignoreRecursive && mode.isSubscript() && vector instanceof RAbstractListVector && positions.length == 1; + } + + @Specialization(limit = "CACHE_LIMIT", guards = {"!isForeignObject(vector)", "cached != null", "cached.isSupported(vector, positions, exact, dropDimensions)"}) + protected Object doExtractDefaultCached(Object vector, Object[] positions, Object exact, Object dropDimensions, // + @Cached("createDefaultCache(getThis(), vector, positions, exact, dropDimensions)") CachedExtractVectorNode cached) { + assert !isRecursiveSubscript(vector, positions); + return cached.apply(vector, positions, null, exact, dropDimensions); + } + + protected static CachedExtractVectorNode createDefaultCache(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) { + return new CachedExtractVectorNode(node.getMode(), (RTypedValue) vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive); + } + + @Specialization(replaces = "doExtractDefaultCached", guards = "!isForeignObject(vector)") + @TruffleBoundary + protected Object doExtractDefaultGeneric(Object vector, Object[] positions, Object exact, Object dropDimensions, // + @Cached("new(createDefaultCache(getThis(), vector, positions, exact, dropDimensions))") GenericVectorExtractNode generic) { + return generic.get(this, vector, positions, exact, dropDimensions).apply(vector, positions, null, exact, dropDimensions); + } + + // TODO hack until Truffle-DSL supports this. + protected ExtractVectorNode getThis() { + return this; + } + + protected static final class GenericVectorExtractNode extends TruffleBoundaryNode { + + @Child private CachedExtractVectorNode cached; + + public GenericVectorExtractNode(CachedExtractVectorNode cachedOperation) { + this.cached = insert(cachedOperation); + } + + public CachedExtractVectorNode get(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) { + CompilerAsserts.neverPartOfCompilation(); + if (!cached.isSupported(vector, positions, exact, dropDimensions)) { + cached = cached.replace(createDefaultCache(node, vector, positions, exact, dropDimensions)); + } + return cached; + } + } + + @Specialization(guards = {"isForeignObject(object)", "positionsByVector(positions)"}) + protected Object accessFieldByVectorPositions(TruffleObject object, Object[] positions, @SuppressWarnings("unused") Object exact, @SuppressWarnings("unused") Object dropDimensions, + @Cached("READ.createNode()") Node foreignRead, + @Cached("KEY_INFO.createNode()") Node keyInfoNode, + @Cached("create()") CastStringNode castNode, + @Cached("createFirstString()") FirstStringNode firstString, + @Cached("IS_NULL.createNode()") Node isNullNode, + @Cached("IS_BOXED.createNode()") Node isBoxedNode, + @Cached("UNBOX.createNode()") Node unboxNode, + @Cached("createForeign2RNode()") Foreign2R foreign2RNode) { + + RAbstractVector vec = (RAbstractVector) positions[0]; + Object[] resultElements = new Object[vec.getLength()]; + InteropTypeCheck typeCheck = new InteropTypeCheck(); + + try { + for (int i = 0; i < vec.getLength(); i++) { + Object res = read(this, vec.getDataAtAsObject(i), foreignRead, keyInfoNode, object, firstString, castNode); + if (RRuntime.isForeignObject(res)) { + if (ForeignAccess.sendIsNull(isNullNode, (TruffleObject) res)) { + res = RNull.instance; + } + if (ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) res)) { + res = ForeignAccess.sendUnbox(unboxNode, (TruffleObject) res); + } + } + typeCheck.check(res); + resultElements[i] = foreign2RNode.execute(res); + } + return ForeignArray2R.asAbstractVector(resultElements, typeCheck); + } catch (InteropException | NoSuchFieldError e) { + throw RError.interopError(RError.findParentRBase(this), e, object); + } + } + + @Specialization(guards = {"isForeignObject(object)", "!positionsByVector(positions)", "positions.length == cachedLength"}) protected Object accessField(TruffleObject object, Object[] positions, @SuppressWarnings("unused") Object exact, @SuppressWarnings("unused") Object dropDimensions, @Cached("READ.createNode()") Node foreignRead, @Cached("KEY_INFO.createNode()") Node keyInfoNode, @@ -126,20 +229,16 @@ public abstract class ExtractVectorNode extends RBaseNode { throw error(RError.Message.GENERIC, "No positions for foreign access."); } try { - try { - // TODO implicite unboxing ok? method calls seem to behave this way - Object result = object; - for (int i = 0; i < pos.length; i++) { - result = read(this, pos[i], foreignRead, keyInfoNode, (TruffleObject) result, firstString, castNode); - if (pos.length > 1 && i < pos.length - 1) { - assert result instanceof TruffleObject; - } + // TODO implicite unboxing ok? method calls seem to behave this way + Object result = object; + for (int i = 0; i < pos.length; i++) { + result = read(this, pos[i], foreignRead, keyInfoNode, (TruffleObject) result, firstString, castNode); + if (pos.length > 1 && i < pos.length - 1) { + assert result instanceof TruffleObject; } - return unbox(result, isNullNode, isBoxedNode, unboxNode, foreign2RNode); - } catch (UnknownIdentifierException | NoSuchFieldError e) { - throw RError.interopError(RError.findParentRBase(this), e, object); } - } catch (InteropException e) { + return unbox(result, isNullNode, isBoxedNode, unboxNode, foreign2RNode); + } catch (InteropException | NoSuchFieldError e) { throw RError.interopError(RError.findParentRBase(this), e, object); } } @@ -190,67 +289,4 @@ public abstract class ExtractVectorNode extends RBaseNode { private static TruffleObject toJavaClass(TruffleObject obj) { return JavaInterop.toJavaClass(obj); } - - @Specialization(guards = {"cached != null", "cached.isSupported(vector, positions)"}) - protected Object doExtractSameDimensions(VirtualFrame frame, RAbstractVector vector, Object[] positions, Object exact, Object dropDimensions, // - @Cached("createRecursiveCache(vector, positions)") RecursiveExtractSubscriptNode cached) { - return cached.apply(frame, vector, positions, exact, dropDimensions); - } - - @Specialization(guards = {"cached != null", "cached.isSupported(vector, positions)"}) - protected Object doExtractRecursive(VirtualFrame frame, RAbstractListVector vector, Object[] positions, Object exact, Object dropDimensions, // - @Cached("createRecursiveCache(vector, positions)") RecursiveExtractSubscriptNode cached) { - return cached.apply(frame, vector, positions, exact, dropDimensions); - } - - protected RecursiveExtractSubscriptNode createRecursiveCache(Object vector, Object[] positions) { - if (isRecursiveSubscript(vector, positions)) { - return RecursiveExtractSubscriptNode.create((RAbstractListVector) vector, positions[0]); - } - return null; - } - - private boolean isRecursiveSubscript(Object vector, Object[] positions) { - return !recursive && !ignoreRecursive && mode.isSubscript() && vector instanceof RAbstractListVector && positions.length == 1; - } - - @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(vector, positions, exact, dropDimensions)"}) - protected Object doExtractDefaultCached(Object vector, Object[] positions, Object exact, Object dropDimensions, // - @Cached("createDefaultCache(getThis(), vector, positions, exact, dropDimensions)") CachedExtractVectorNode cached) { - assert !isRecursiveSubscript(vector, positions); - return cached.apply(vector, positions, null, exact, dropDimensions); - } - - protected static CachedExtractVectorNode createDefaultCache(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) { - return new CachedExtractVectorNode(node.getMode(), (RTypedValue) vector, positions, (RTypedValue) exact, (RTypedValue) dropDimensions, node.recursive); - } - - @Specialization(replaces = "doExtractDefaultCached") - @TruffleBoundary - protected Object doExtractDefaultGeneric(Object vector, Object[] positions, Object exact, Object dropDimensions, // - @Cached("new(createDefaultCache(getThis(), vector, positions, exact, dropDimensions))") GenericVectorExtractNode generic) { - return generic.get(this, vector, positions, exact, dropDimensions).apply(vector, positions, null, exact, dropDimensions); - } - - // TODO hack until Truffle-DSL supports this. - protected ExtractVectorNode getThis() { - return this; - } - - protected static final class GenericVectorExtractNode extends TruffleBoundaryNode { - - @Child private CachedExtractVectorNode cached; - - public GenericVectorExtractNode(CachedExtractVectorNode cachedOperation) { - this.cached = insert(cachedOperation); - } - - public CachedExtractVectorNode get(ExtractVectorNode node, Object vector, Object[] positions, Object exact, Object dropDimensions) { - CompilerAsserts.neverPartOfCompilation(); - if (!cached.isSupported(vector, positions, exact, dropDimensions)) { - cached = cached.replace(createDefaultCache(node, vector, positions, exact, dropDimensions)); - } - return cached; - } - } } 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 03ef1cf845..d3999179c1 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 @@ -61,7 +61,6 @@ public abstract class ForeignArray2R extends RBaseNode { @Specialization(guards = {"isArray(obj, hasSize)"}) @TruffleBoundary public RAbstractVector doArray(TruffleObject obj, - @SuppressWarnings("unused") @Cached("HAS_SIZE.createNode()") Node hasSize, @Cached("GET_SIZE.createNode()") Node getSize) { int size; try { @@ -71,12 +70,7 @@ public abstract class ForeignArray2R extends RBaseNode { } CollectedElements ce = getArrayElements(size, obj); - RAbstractVector ret = toVector(ce); - if (ret != null) { - return ret; - } else { - return RDataFactory.createList(ce.elements); - } + return asAbstractVector(ce.elements, ce.typeCheck); } catch (UnsupportedMessageException | UnknownIdentifierException e) { throw error(RError.Message.GENERIC, "error while converting array: " + e.getMessage()); } @@ -89,11 +83,7 @@ public abstract class ForeignArray2R extends RBaseNode { try { CollectedElements ce = getIterableElements(obj, execute); - RAbstractVector ret = toVector(ce); - if (ret != null) { - return ret; - } - return RDataFactory.createList(ce.elements); + return asAbstractVector(ce.elements, ce.typeCheck); } catch (UnsupportedMessageException | UnknownIdentifierException | UnsupportedTypeException | ArityException e) { throw error(RError.Message.GENERIC, "error while casting external object to list: " + e.getMessage()); } @@ -166,11 +156,7 @@ public abstract class ForeignArray2R extends RBaseNode { } } } - - ce.allBoolean &= value instanceof Boolean; - ce.allInteger &= value instanceof Byte || value instanceof Integer || value instanceof Short; - ce.allDouble &= value instanceof Double || value instanceof Float || value instanceof Long; - ce.allString &= value instanceof Character || value instanceof String; + ce.typeCheck.check(value); if (foreign2R == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -179,35 +165,45 @@ public abstract class ForeignArray2R extends RBaseNode { return foreign2R.execute(value); } - protected RAbstractVector toVector(CollectedElements ce) { - int size = ce.elements.length; - if (ce.allBoolean) { - byte[] ret = new byte[size]; - for (int i = 0; i < size; i++) { - ret[i] = ((Number) ce.elements[i]).byteValue(); - } - return RDataFactory.createLogicalVector(ret, true); - } - if (ce.allInteger) { - int[] ret = new int[size]; - for (int i = 0; i < size; i++) { - ret[i] = ((Number) ce.elements[i]).intValue(); - } - return RDataFactory.createIntVector(ret, true); + public static RAbstractVector asAbstractVector(Object[] elements, InteropTypeCheck typeCheck) { + InteropTypeCheck.RType type = typeCheck.getType(); + if (type == null) { + return RDataFactory.createList(elements); } - if (ce.allDouble) { - double[] ret = new double[size]; - for (int i = 0; i < size; i++) { - ret[i] = ((Number) ce.elements[i]).doubleValue(); - } - return RDataFactory.createDoubleVector(ret, true); - } - if (ce.allString) { - String[] ret = new String[size]; - for (int i = 0; i < size; i++) { - ret[i] = String.valueOf(ce.elements[i]); - } - return RDataFactory.createStringVector(ret, true); + int size = elements.length; + // TODO how to deal with NAs? + boolean complete = true; + switch (type) { + case BOOLEAN: + byte[] bytes = new byte[size]; + for (int i = 0; i < size; i++) { + bytes[i] = ((Number) elements[i]).byteValue(); + complete &= RRuntime.isNA(bytes[i]); + } + return RDataFactory.createLogicalVector(bytes, complete); + case DOUBLE: + double[] doubles = new double[size]; + for (int i = 0; i < size; i++) { + doubles[i] = ((Number) elements[i]).doubleValue(); + complete &= RRuntime.isNA(doubles[i]); + } + return RDataFactory.createDoubleVector(doubles, complete); + case INTEGER: + int[] ints = new int[size]; + for (int i = 0; i < size; i++) { + ints[i] = ((Number) elements[i]).intValue(); + complete &= RRuntime.isNA(ints[i]); + } + return RDataFactory.createIntVector(ints, complete); + case STRING: + String[] strings = new String[size]; + for (int i = 0; i < size; i++) { + strings[i] = String.valueOf(elements[i]); + complete &= RRuntime.isNA(strings[i]); + } + return RDataFactory.createStringVector(strings, complete); + default: + assert false; } return null; } @@ -220,11 +216,48 @@ public abstract class ForeignArray2R extends RBaseNode { return RRuntime.isForeignObject(obj) && JavaInterop.isJavaObject(Iterable.class, obj); } + public static class InteropTypeCheck { + public enum RType { + BOOLEAN, + DOUBLE, + INTEGER, + STRING; + } + + private RType type = null; + private boolean sameRType = true; + + public void check(Object value) { + if (value instanceof Boolean) { + setType(RType.BOOLEAN); + } else if (value instanceof Byte || value instanceof Integer || value instanceof Short) { + setType(RType.INTEGER); + } else if (value instanceof Double || value instanceof Float || value instanceof Long) { + setType(RType.DOUBLE); + } else if (value instanceof Character || value instanceof String) { + setType(RType.STRING); + } else { + this.type = null; + sameRType = false; + } + } + + private void setType(RType check) { + if (sameRType && this.type == null) { + this.type = check; + } else if (this.type != check) { + this.type = null; + sameRType = false; + } + } + + public RType getType() { + return sameRType ? type : null; + } + } + private class CollectedElements { Object[] elements; - boolean allBoolean = true; - boolean allInteger = true; - boolean allDouble = true; - boolean allString = true; + InteropTypeCheck typeCheck = new InteropTypeCheck(); } } 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 4e8f27c9ff..2ffa78dee1 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 @@ -131257,6 +131257,14 @@ $longValue #if (!any(R.version$engine == "FastR")) { "true127a32767214748364792233720368547758071.7976931348623157E3083.4028235E38testString" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); to$allTypesStaticMethod(TRUE,127,"a",32767,2147483647,9223372036854775807,1.7976931348623157E308,3.4028235E38,"testString") } [1] "true127a32767214748364792233720368547758071.7976931348623157E3083.4028235E38testString" +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testArrayAsParameter# +#if (!any(R.version$engine == "FastR")) { '[I' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));ja <- as.java.array(c(1L, 2L, 3L), 'int'); to$isIntArray(ja) } +[1] "[I" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testArrayAsParameter# +#if (!any(R.version$engine == "FastR")) { '[Ljava.lang.Integer;' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));ja <- as.java.array(c(1L, 2L, 3L), 'java.lang.Integer'); to$isIntegerArray(ja) } +[1] "[Ljava.lang.Integer;" + ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testArrayReadWrite# #if (!any(R.version$engine == "FastR")) { 1 } else { a <- as.java.array(c(1,2,3)); a[1] } [1] 1 @@ -132900,6 +132908,10 @@ Error in attr(to, which = "a") : external object cannot be attributed #if (!any(R.version$engine == "FastR")) { c('a', 'b', 'c', 'a', 'b', 'c') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); c(to$listString, to$listString) } [1] "a" "b" "c" "a" "b" "c" +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testConvertEmptyList#Ignored.ImplementationError# +#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.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" @@ -133152,6 +133164,128 @@ NULL [external object] [1] 1.1 2.1 3.1 +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "character" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticCharArray); typeof(v) } +[1] "character" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "character" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticStringArray); typeof(v) } +[1] "character" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "double" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticDoubleArray); typeof(v) } +[1] "double" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "double" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticFloatArray); typeof(v) } +[1] "double" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "double" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticLongArray); typeof(v) } +[1] "double" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "double" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$objectDoubleArray); typeof(v) } +[1] "double" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "integer" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticByteArray); typeof(v) } +[1] "integer" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "integer" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticIntegerArray); typeof(v) } +[1] "integer" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "integer" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticShortArray); typeof(v) } +[1] "integer" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "integer" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$objectIntArray); typeof(v) } +[1] "integer" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { "logical" } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticBooleanArray); typeof(v) } +[1] "logical" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- .fastr.interop.fromArray(to$hasNullIntArray); is.list(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- .fastr.interop.fromArray(to$mixedTypesArray); is.list(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- .fastr.interop.fromArray(to$objectArray); is.list(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticBooleanArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticByteArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticCharArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticDoubleArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticFloatArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticIntegerArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticLongArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticShortArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$fieldStaticStringArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$objectDoubleArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { TRUE } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- as.vector(to$objectIntArray); is.vector(v) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { list() } else { ja <- new.java.array('java.lang.String', 0L); .fastr.interop.fromArray(ja) } +list() + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { list(1) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- .fastr.interop.fromArray(to$hasNullIntArray); v[1] } +[[1]] +[1] 1 + + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { list(3) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- .fastr.interop.fromArray(to$hasNullIntArray); v[3] } +[[1]] +[1] 3 + + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFromArray# +#if (!any(R.version$engine == "FastR")) { list(NULL) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); v <- .fastr.interop.fromArray(to$hasNullIntArray); v[2] } +[[1]] +NULL + + ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testGetClass# #if (!any(R.version$engine == "FastR")) { 'com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'));java.class(to) } [1] "com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass" @@ -133506,6 +133640,22 @@ Error in is.infinite(to) : Error in is.nan(to) : default method not implemented for type 'external object' +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMap# +#if (!any(R.version$engine == "FastR")) { '1' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); m <- to$map; m['one'] } +[1] "1" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMap#Ignored.Unimplemented# +#if (!any(R.version$engine == "FastR")) { '11' } else { how to put into map? } +Error: unexpected symbol in "if (!any(R.version$engine == "FastR")) { '11' } else { how to" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMap# +#if (!any(R.version$engine == "FastR")) { '11' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); m <- to$map; m['one']<-'11'; m['one'] } +[1] "11" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMap# +#if (!any(R.version$engine == "FastR")) { '2' } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); m <- to$map; m['two'] } +[1] "2" + ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# #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$methodStaticStringObject() } [1] "a string" @@ -134352,6 +134502,27 @@ Error: object 'java.lang.String' not found #if (!any(R.version$engine == "FastR")) { 'short' } else { toc <- new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestOverload'); toc$isOverloaded(as.external.short(1)) } [1] "short" +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testReadByVector# +#if (!any(R.version$engine == "FastR")) { c('1', '3') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); to$map[c('one', 'three')] } +[1] "1" "3" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testReadByVector# +#if (!any(R.version$engine == "FastR")) { c('a string', 'a') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); to[c('fieldStringObject', 'fieldChar')] } +[1] "a string" "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testReadByVector# +#if (!any(R.version$engine == "FastR")) { c('a', 'c') } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); to$fieldStringArray[c(1, 3)] } +[1] "a" "c" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testReadByVector# +#if (!any(R.version$engine == "FastR")) { list('a string', 2147483647) } else { to <- new.external(new.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass')); to[c('fieldStringObject', 'fieldInteger')] } +[[1]] +[1] "a string" + +[[2]] +[1] 2147483647 + + ##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToArray# #if (!any(R.version$engine == "FastR")) { '[B' } else { a <- as.java.array(as.raw(1)); java.class(a); } [1] "[B" 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 6776621532..9b8c05231c 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 @@ -196,6 +196,12 @@ public class TestJavaInterop extends TestBase { assertEvalFastR(Ignored.Unimplemented, "a <- as.java.array(1L,,F); a;", getRValue(new int[]{1})); } + @Test + public void testArrayAsParameter() { + assertEvalFastR(CREATE_TRUFFLE_OBJECT + "ja <- as.java.array(c(1L, 2L, 3L), 'int'); to$isIntArray(ja)", "'" + (new int[1]).getClass().getName() + "'"); + assertEvalFastR(CREATE_TRUFFLE_OBJECT + "ja <- as.java.array(c(1L, 2L, 3L), 'java.lang.Integer'); to$isIntegerArray(ja)", "'" + (new Integer[1]).getClass().getName() + "'"); + } + @Test public void testNewArray() { testNewArray("java.lang.Boolean", true); @@ -268,6 +274,31 @@ public class TestJavaInterop extends TestBase { assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- as.vector(to$hasNullIntArray); v[3]", "list(3)"); } + @Test + public void testFromArray() { + testAsVectorFromArray("fieldStaticBooleanArray", "logical"); + testAsVectorFromArray("fieldStaticByteArray", "integer"); + testAsVectorFromArray("fieldStaticCharArray", "character"); + testAsVectorFromArray("fieldStaticDoubleArray", "double"); + testAsVectorFromArray("fieldStaticFloatArray", "double"); + testAsVectorFromArray("fieldStaticIntegerArray", "integer"); + testAsVectorFromArray("fieldStaticLongArray", "double"); + testAsVectorFromArray("fieldStaticShortArray", "integer"); + testAsVectorFromArray("fieldStaticStringArray", "character"); + + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- .fastr.interop.fromArray(to$objectArray); is.list(v)", "TRUE"); + testAsVectorFromArray("objectIntArray", "integer"); + testAsVectorFromArray("objectDoubleArray", "double"); + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- .fastr.interop.fromArray(to$mixedTypesArray); is.list(v)", "TRUE"); + + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- .fastr.interop.fromArray(to$hasNullIntArray); is.list(v)", "TRUE"); + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- .fastr.interop.fromArray(to$hasNullIntArray); v[1]", "list(1)"); + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- .fastr.interop.fromArray(to$hasNullIntArray); v[2]", "list(NULL)"); + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- .fastr.interop.fromArray(to$hasNullIntArray); v[3]", "list(3)"); + + assertEvalFastR("ja <- new.java.array('java.lang.String', 0L); .fastr.interop.fromArray(ja)", "list()"); + } + public void testAsVectorFromArray(String field, String type) { assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- as.vector(to$" + field + "); is.vector(v)", "TRUE"); assertEvalFastR(CREATE_TRUFFLE_OBJECT + " v <- as.vector(to$" + field + "); typeof(v)", getRValue(type)); @@ -441,6 +472,17 @@ public class TestJavaInterop extends TestBase { assertEvalFastR(CREATE_TRUFFLE_OBJECT + " to$int2DimArray[[1,2]] <- 12345L; to$int2DimArray[[1,2]]", "12345"); } + @Test + public void testReadByVector() { + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " to$fieldStringArray[c(1, 3)]", "c('a', 'c')"); + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " to$map[c('one', 'three')]", "c('1', '3')"); + + TestClass tc = new TestClass(); + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " to[c('fieldStringObject', 'fieldChar')]", "c('" + tc.fieldStringObject + "', '" + tc.fieldChar + "')"); + assertEvalFastR(CREATE_TRUFFLE_OBJECT + " to[c('fieldStringObject', 'fieldInteger')]", "list('" + tc.fieldStringObject + "', " + tc.fieldInteger + ")"); + } + + @Test public void testMap() { assertEvalFastR(CREATE_TRUFFLE_OBJECT + " m <- to$map; m['one']", "'1'"); assertEvalFastR(CREATE_TRUFFLE_OBJECT + " m <- to$map; m['two']", "'2'"); @@ -589,6 +631,11 @@ public class TestJavaInterop extends TestBase { assertEvalFastR(Output.IgnoreErrorContext, CREATE_TRUFFLE_OBJECT + " l<-as.list(to);", "cat('Error in as.list(to) : ', '\n', ' no method for coercing this external object to a list', '\n')"); } + @Test + public void testConvertEmptyList() throws IllegalArgumentException, IllegalAccessException { + assertEvalFastR(Ignored.ImplementationError, CREATE_TRUFFLE_OBJECT + "as.character(to$listEmpty);", "as.character(list())"); + } + @Test public void testAsXXX() throws IllegalArgumentException, IllegalAccessException { testAsXXX("as.character"); @@ -1168,6 +1215,7 @@ public class TestJavaInterop extends TestBase { public List<String> listString = new ArrayList<>(Arrays.asList("a", "b", "c")); public List<String> listStringInt = new ArrayList<>(Arrays.asList("1", "2", "3")); public List<String> listStringBoolean = new ArrayList<>(Arrays.asList("TRUE", "TRUE", "FALSE")); + public List<String> listEmpty = new ArrayList<>(); public static class Element { public final String data; @@ -1255,6 +1303,7 @@ public class TestJavaInterop extends TestBase { map = new HashMap<>(); map.put("one", "1"); map.put("two", "2"); + map.put("three", "3"); } public static boolean methodStaticBoolean() { @@ -1444,6 +1493,82 @@ public class TestJavaInterop extends TestBase { public boolean equals(TestClass tc) { return tc == this; } + + public String isOverloaded(boolean b) { + return "boolean"; + } + + public String isOverloaded(Boolean b) { + return Boolean.class.getName(); + } + + public String isOverloaded(byte b) { + return "byte"; + } + + public String isOverloaded(Byte b) { + return Byte.class.getName(); + } + + public String isOverloaded(char c) { + return "char"; + } + + public String isOverloaded(Character c) { + return Character.class.getName(); + } + + public String isOverloaded(double l) { + return "double"; + } + + public String isOverloaded(Double l) { + return Double.class.getName(); + } + + public String isOverloaded(Float f) { + return Float.class.getName(); + } + + public String isOverloaded(float f) { + return "float"; + } + + public String isOverloaded(int c) { + return "int"; + } + + public String isOverloaded(Integer c) { + return Integer.class.getName(); + } + + public String isOverloaded(long l) { + return "long"; + } + + public String isOverloaded(Long l) { + return Long.class.getName(); + } + + public String isOverloaded(short c) { + return "short"; + } + + public String isOverloaded(Short c) { + return Short.class.getName(); + } + + public String isOverloaded(String s) { + return String.class.getName(); + } + + public String isIntArray(int[] a) { + return a.getClass().getName(); + } + + public String isIntegerArray(Integer[] a) { + return a.getClass().getName(); + } } public static class TestArrayClass { -- GitLab