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 241fd56c01eca4051308d409096072619f128d9f..3fda7060a46f2c63769011664af3e5a4dc325c42 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 @@ -376,6 +376,11 @@ public class BasePackage extends RBuiltinPackage { add(FastRInterop.IsExecutable.class, FastRInteropFactory.IsExecutableNodeGen::create); add(FastRInterop.JavaClass.class, FastRInteropFactory.JavaClassNodeGen::create); add(FastRInterop.ToBoolean.class, FastRInteropFactory.ToBooleanNodeGen::create); + add(FastRInterop.ToByte.class, FastRInteropFactory.ToByteNodeGen::create); + add(FastRInterop.ToChar.class, FastRInteropFactory.ToCharNodeGen::create); + add(FastRInterop.ToFloat.class, FastRInteropFactory.ToFloatNodeGen::create); + add(FastRInterop.ToLong.class, FastRInteropFactory.ToLongNodeGen::create); + add(FastRInterop.ToShort.class, FastRInteropFactory.ToShortNodeGen::create); add(FastRRefCountInfo.class, FastRRefCountInfoNodeGen::create); add(FastRPkgSource.class, FastRPkgSourceNodeGen::create); add(FastRStackTrace.class, FastRStackTraceNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java index 4104af4f437e3f09f890c93b2cee38ebf921876f..0bd88751d6643cdb10f595f18ad40e3a5b98507f 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ValuePrinters.java @@ -35,6 +35,7 @@ import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RExternalPtr; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RInteropScalar; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPairList; @@ -75,7 +76,7 @@ final class ValuePrinters implements ValuePrinter<Object> { if (v == RNull.instance) { NullPrinter.INSTANCE.print(null, printCtx); } else { - // handle types that can appear via Truffle interop + // handle types that are meant for or can appear via Truffle interop Object x = v; if (x instanceof Boolean) { x = RRuntime.asLogical((Boolean) x); @@ -83,6 +84,8 @@ final class ValuePrinters implements ValuePrinter<Object> { x = ((Number) x).doubleValue(); } else if (x instanceof Character) { x = ((Character) x).toString(); + } else if (x instanceof RInteropScalar) { + x = ((RInteropScalar) x).getRValue(); } // try to box a scalar primitive value to the respective vector x = printCtx.printerNode().boxPrimitive(x); 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 912beabdbf0da3918da1bdfbe295e03b7822cea5..fee1e92a2995cce386ff1356904eae268dafcb62 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 @@ -45,30 +45,50 @@ 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.UnknownIdentifierException; 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.profiles.ConditionProfile; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.Source.Builder; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.doubleValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.integerValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.numericValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.rawValue; +import static com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef.typeName; +import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RError.Message; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSource; +import static com.oracle.truffle.r.runtime.RType.Array; 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.RDataFactory; +import com.oracle.truffle.r.runtime.data.RInteropScalar; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropByte; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropChar; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropFloat; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropLong; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropShort; +import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.data.RRaw; 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.RAbstractIntVector; 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; +import com.oracle.truffle.r.runtime.data.model.RAbstractVector; +import java.util.logging.Level; +import java.util.logging.Logger; public class FastRInterop { @@ -165,7 +185,7 @@ public class FastRInterop { @TruffleBoundary protected Object exportSymbol(String name, RTypedValue value) { if (name == null) { - throw error(RError.Message.INVALID_ARG_TYPE, "name"); + throw error(RError.Message.INVALID_ARGUMENT, "name"); } RContext.getInstance().getExportedSymbols().put(name, value); return RNull.instance; @@ -228,7 +248,7 @@ public class FastRInterop { } @Specialization - public byte hasSize(TruffleObject obj) { + public byte isNull(TruffleObject obj) { return RRuntime.asLogical(ForeignAccess.sendIsNull(node, obj)); } } @@ -243,11 +263,149 @@ public class FastRInterop { } @Specialization - public byte hasSize(TruffleObject obj) { + public byte isExecutable(TruffleObject obj) { return RRuntime.asLogical(ForeignAccess.sendIsExecutable(node, obj)); } } + @RBuiltin(name = ".fastr.interop.toByte", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX) + public abstract static class ToByte extends RBuiltinNode.Arg1 { + + static { + castToJavaNumberType(new Casts(ToByte.class)); + } + + @Specialization + public RInteropByte toByte(int value) { + return RInteropByte.valueOf((byte) value); + } + + @Specialization + public RInteropByte toByte(double value) { + return RInteropByte.valueOf((byte) value); + } + + @Specialization + public RInteropByte toByte(RRaw value) { + return RInteropByte.valueOf(value.getValue()); + } + } + + @RBuiltin(name = ".fastr.interop.toChar", visibility = ON, kind = PRIMITIVE, parameterNames = {"value", "pos"}, behavior = COMPLEX) + public abstract static class ToChar extends RBuiltinNode.Arg2 { + + static { + Casts casts = new Casts(ToChar.class); + casts.arg("value").mustBe(integerValue().or(doubleValue().or(stringValue())), RError.Message.INVALID_ARGUMENT_OF_TYPE, "value", Predef.typeName()).asVector().mustBe( + singleElement()).findFirst(); + casts.arg("pos").allowMissing().mustBe(numericValue(), RError.Message.INVALID_ARGUMENT_OF_TYPE, "pos", Predef.typeName()).asIntegerVector().mustBe(singleElement()).findFirst(); + } + + @Specialization + public RInteropChar toChar(int value, @SuppressWarnings("unused") RMissing unused) { + return RInteropChar.valueOf((char) value); + } + + @Specialization + public RInteropChar toChar(double value, @SuppressWarnings("unused") RMissing unused) { + return RInteropChar.valueOf((char) value); + } + + @Specialization + public RInteropChar toChar(String value, @SuppressWarnings("unused") RMissing unused) { + return toChar(value, 0); + } + + @Specialization + public RInteropChar toChar(int value, int pos) { + throw RError.error(this, RError.Message.POS_NOT_ALLOWED_WITH_NUMERIC); + } + + @Specialization + public RInteropChar toChar(double value, int pos) { + throw RError.error(this, RError.Message.POS_NOT_ALLOWED_WITH_NUMERIC); + } + + @Specialization + public RInteropChar toChar(String value, int pos) { + return RInteropChar.valueOf(value.charAt(pos)); + } + } + + @RBuiltin(name = ".fastr.interop.toFloat", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX) + public abstract static class ToFloat extends RBuiltinNode.Arg1 { + + static { + castToJavaNumberType(new Casts(ToFloat.class)); + } + + @Specialization + public RInteropFloat toFloat(int value) { + return RInteropFloat.valueOf((float) value); + } + + @Specialization + public RInteropFloat toFloat(double value) { + return RInteropFloat.valueOf((float) value); + } + + @Specialization + public RInteropFloat toFloat(RRaw value) { + return RInteropFloat.valueOf(value.getValue()); + } + } + + @RBuiltin(name = ".fastr.interop.toLong", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX) + public abstract static class ToLong extends RBuiltinNode.Arg1 { + + static { + castToJavaNumberType(new Casts(ToLong.class)); + } + + @Specialization + public RInteropLong toLong(int value) { + return RInteropLong.valueOf((long) value); + } + + @Specialization + public RInteropLong toLong(double value) { + return RInteropLong.valueOf((long) value); + } + + @Specialization + public RInteropLong toLong(RRaw value) { + return RInteropLong.valueOf(value.getValue()); + } + } + + @RBuiltin(name = ".fastr.interop.toShort", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX) + public abstract static class ToShort extends RBuiltinNode.Arg1 { + + static { + castToJavaNumberType(new Casts(ToShort.class)); + } + + @Specialization + public RInteropShort toShort(double value) { + return RInteropShort.valueOf((short) value); + } + + @Specialization + public RInteropShort toShort(int value) { + return RInteropShort.valueOf((short) value); + } + + @Specialization + public RInteropShort toShort(RRaw value) { + return RInteropShort.valueOf(value.getValue()); + } + + } + + private static void castToJavaNumberType(Casts casts) { + casts.arg("value").mustBe(integerValue().or(doubleValue().or(rawValue())), RError.Message.INVALID_ARGUMENT_OF_TYPE, "value", Predef.typeName()).asVector().mustBe(singleElement()).findFirst(); + } + @RBuiltin(name = ".fastr.interop.toBoolean", visibility = ON, kind = PRIMITIVE, parameterNames = {"value"}, behavior = COMPLEX) public abstract static class ToBoolean extends RBuiltinNode.Arg1 { @@ -281,32 +439,349 @@ public class FastRInterop { } } - @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.Arg2 { + @ImportStatic({Message.class, RRuntime.class}) + @RBuiltin(name = ".fastr.java.isArray", visibility = ON, kind = PRIMITIVE, parameterNames = {"obj"}, behavior = COMPLEX) + public abstract static class IsJavaArray extends RBuiltinNode.Arg1 { static { - Casts.noCasts(InteropNew.class); + Casts.noCasts(IsJavaArray.class); + } + + private final ConditionProfile isJavaProfile = ConditionProfile.createBinaryProfile(); + private final ConditionProfile isArrayProfile = ConditionProfile.createBinaryProfile(); + + @Specialization(guards = {"isForeignObject(obj)"}) + @TruffleBoundary + public Object isArray(TruffleObject obj) { + // TODO does this return true only for java arrays, or also + // js arrays? + boolean result = isJavaProfile.profile(JavaInterop.isJavaObject(Object.class, obj)) && isArrayProfile.profile(JavaInterop.isArray(obj)); + return RRuntime.java2R(result); + } + + @Fallback + public Object isArray(Object obj) { + return RRuntime.java2R(false); + } + } + + @RBuiltin(name = ".fastr.java.newArray", visibility = ON, kind = PRIMITIVE, parameterNames = {"class", "dim"}, behavior = COMPLEX) + public abstract static class NewJavaArray extends RBuiltinNode.Arg2 { + + static { + Casts casts = new Casts(NewJavaArray.class); + casts.arg("class").mustBe(stringValue()).asStringVector().mustBe(Predef.singleElement()).findFirst(); + casts.arg("dim").mustBe(integerValue(), RError.Message.INVALID_ARGUMENT_OF_TYPE, "dim", typeName()).asIntegerVector(); + } + + @Specialization + @TruffleBoundary + public Object newArray(String clazz, int length) { + try { + // TODO new via ForeignAccess + return JavaInterop.asTruffleObject(Array.newInstance(Class.forName(clazz), length)); + } catch (ClassNotFoundException e) { + throw error(RError.Message.GENERIC, "error while accessing Java class: " + e.getMessage()); + } } - 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); + @Specialization + @TruffleBoundary + public Object newArray(String clazz, RAbstractIntVector dim) { + try { + int[] dima = new int[dim.getLength()]; + // TODO new via ForeignAccess + return JavaInterop.asTruffleObject(Array.newInstance(Class.forName(clazz), dima)); + } catch (ClassNotFoundException e) { + throw error(RError.Message.GENERIC, "error while accessing Java class: " + e.getMessage()); + } + } + } + + @ImportStatic({Message.class, RRuntime.class}) + @RBuiltin(name = ".fastr.java.toArray", visibility = ON, kind = PRIMITIVE, parameterNames = {"x", "className", "flat"}, behavior = COMPLEX) + public abstract static class ToJavaArray extends RBuiltinNode.Arg3 { + + static { + Casts casts = new Casts(ToJavaArray.class); + casts.arg("x").mustNotBeMissing(); + casts.arg("className").allowMissing().mustBe(stringValue()).asStringVector().mustBe(Predef.singleElement()).findFirst(); + casts.arg("flat").mapMissing(Predef.constant(RRuntime.asLogical(true))).mustBe(logicalValue().or(Predef.nullValue())).asLogicalVector().mustBe(singleElement()).findFirst().mustBe( + notLogicalNA()).map(Predef.toBoolean()); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractLogicalVector vec, @SuppressWarnings("unused") RMissing className, boolean flat) { + return toArray(vec, flat, boolean.class, (array, i) -> Array.set(array, i, RRuntime.r2Java(vec.getDataAt(i)))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractLogicalVector vec, String className, boolean flat) { + return toArray(vec, flat, getClazz(className), (array, i) -> Array.set(array, i, RRuntime.r2Java(vec.getDataAt(i)))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractIntVector vec, @SuppressWarnings("unused") RMissing className, boolean flat) { + return toArray(vec, flat, int.class, (array, i) -> Array.set(array, i, RRuntime.r2Java(vec.getDataAt(i)))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractIntVector vec, String className, boolean flat) { + return toArray(vec, flat, getClazz(className), (array, i) -> Array.set(array, i, vec.getDataAt(i))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractDoubleVector vec, @SuppressWarnings("unused") RMissing className, boolean flat) { + return toArray(vec, flat, double.class, (array, i) -> Array.set(array, i, vec.getDataAt(i))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractDoubleVector vec, String className, boolean flat) { + return toArray(vec, flat, getClazz(className), (array, i) -> Array.set(array, i, vec.getDataAt(i))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractStringVector vec, @SuppressWarnings("unused") RMissing className, boolean flat) { + return toArray(vec, flat, String.class, (array, i) -> Array.set(array, i, vec.getDataAt(i))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractStringVector vec, String className, boolean flat) { + return toArray(vec, flat, getClazz(className), (array, i) -> Array.set(array, i, vec.getDataAt(i))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractVector vec, @SuppressWarnings("unused") RMissing className, boolean flat) { + return toArray(vec, flat, Object.class, (array, i) -> Array.set(array, i, RRuntime.r2Java(vec.getDataAtAsObject(i)))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RAbstractVector vec, String className, boolean flat) { + return toArray(vec, flat, getClazz(className), (array, i) -> Array.set(array, i, RRuntime.r2Java(vec.getDataAtAsObject(i)))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RInteropScalar ri, String className, boolean flat) { + RList list = RDataFactory.createList(new Object[]{ri}); + return toArray(list, flat, getClazz(className), (array, i) -> Array.set(array, i, RRuntime.r2Java(list.getDataAt(i)))); + } + + @Specialization + @TruffleBoundary + public Object toArray(RInteropScalar ri, RMissing className, boolean flat) { + RList list = RDataFactory.createList(new Object[]{ri}); + return toArray(list, flat, ri.getJavaType(), (array, i) -> Array.set(array, i, RRuntime.r2Java(list.getDataAt(i)))); + } + + private Class<?> getClazz(String className) throws RError { + if (className.equals(Byte.TYPE.getName())) { + return Byte.TYPE; + } + if (className.equals(Boolean.TYPE.getName())) { + return Boolean.TYPE; + } + if (className.equals(Character.TYPE.getName())) { + return Character.TYPE; + } + if (className.equals(Double.TYPE.getName())) { + return Double.TYPE; + } + if (className.equals(Float.TYPE.getName())) { + return Float.TYPE; + } + if (className.equals(Integer.TYPE.getName())) { + return Integer.TYPE; + } + if (className.equals(Long.TYPE.getName())) { + return Long.TYPE; + } + if (className.equals(Short.TYPE.getName())) { + return Short.TYPE; + } + try { + return Class.forName(className); + } catch (ClassNotFoundException e) { + throw error(RError.Message.GENERIC, "error while accessing Java class: " + e.getMessage()); + } + } + + private int[] getDim(boolean flat, RAbstractVector vec) { + int[] dims; + if (flat) { + dims = new int[]{vec.getLength()}; + } else { + dims = vec.getDimensions(); + if (dims == null) { + dims = new int[]{vec.getLength()}; } } - return value; + return dims; + } + + private Object toArray(RAbstractVector vec, boolean flat, Class<?> clazz, VecElementToArray vecToArray) throws IllegalArgumentException, ArrayIndexOutOfBoundsException { + int[] dims = getDim(flat, vec); + final Object array = Array.newInstance(clazz, dims); + for (int d = 0; d < dims.length; d++) { + int dim = dims[d]; + // TODO works only for flat + for (int i = 0; i < dim; i++) { + vecToArray.toArray(array, i); + } + } + return JavaInterop.asTruffleObject(array); + } + + private interface VecElementToArray { + void toArray(Object array, Integer i); + } + + @Specialization + @TruffleBoundary + public Object toArray(TruffleObject obj, @SuppressWarnings("unused") RMissing missing, @SuppressWarnings("unused") boolean flat, + @Cached("WRITE.createNode()") Node write) { + if (JavaInterop.isJavaObject(Object.class, obj)) { + if (JavaInterop.isArray(obj)) { + // TODO should return copy? + return obj; + } + try { + // TODO should create array with the same component type as the JavaObject + TruffleObject array = JavaInterop.asTruffleObject(Array.newInstance(Object.class, 1)); + ForeignAccess.sendWrite(write, array, 0, obj); + return array; + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw error(RError.Message.GENERIC, "error while creating array: " + e.getMessage()); + } catch (UnsupportedTypeException ex) { + Logger.getLogger(FastRInterop.class.getName()).log(Level.SEVERE, null, ex); + } + } + throw error(RError.Message.GENERIC, "can't create array from " + obj); + } + + @Fallback + public Object toArray(Object o, @SuppressWarnings("unused") Object className, @SuppressWarnings("unused") Object flat) { + throw error(RError.Message.GENERIC, "unsupported type"); + } + + } + + @RBuiltin(name = ".fastr.java.fromArray", visibility = ON, kind = PRIMITIVE, parameterNames = {"array"}, behavior = COMPLEX) + public abstract static class FromJavaArray extends RBuiltinNode.Arg1 { + @Child Node getSize = Message.GET_SIZE.createNode(); + @Child Node read; + @Child Node isNull; + @Child Node isBoxed; + @Child Node unbox; + static { + Casts casts = new Casts(FromJavaArray.class); + casts.arg("array").mustNotBeMissing(); + } + + protected boolean isJavaArray(TruffleObject obj) { + return JavaInterop.isJavaObject(Object.class, obj) && JavaInterop.isArray(obj); + } + + @Specialization(guards = {"isJavaArray(obj)"}) + @TruffleBoundary + public Object fromArray(TruffleObject obj) { + int size; + try { + size = (int) ForeignAccess.sendGetSize(getSize, obj); + if (size == 0) { + return RDataFactory.createList(); + } + Object[] elements = new Object[size]; + boolean allBoolean = true; + boolean allInteger = true; + boolean allDouble = true; + boolean allString = true; + for (int i = 0; i < size; i++) { + if (read == null) { + read = insert(Message.READ.createNode()); + } + Object element = ForeignAccess.sendRead(read, obj, i); + if (element instanceof TruffleObject) { + if (isNull == null) { + isNull = insert(Message.IS_NULL.createNode()); + } + if (ForeignAccess.sendIsNull(isNull, (TruffleObject) element)) { + element = null; + } else { + if (isBoxed == null) { + isBoxed = insert(Message.IS_BOXED.createNode()); + } + if (ForeignAccess.sendIsBoxed(isBoxed, (TruffleObject) element)) { + if (unbox == null) { + unbox = insert(Message.UNBOX.createNode()); + } + element = ForeignAccess.sendIsBoxed(unbox, (TruffleObject) element); + } + } + } + allBoolean &= element instanceof Boolean; + allInteger &= element instanceof Byte || element instanceof Integer || element instanceof Short; + allDouble &= element instanceof Double || element instanceof Float || element instanceof Long; + allString &= element instanceof Character || element instanceof String; + + elements[i] = RRuntime.java2R(element); + } + if (allBoolean) { + byte[] ret = new byte[size]; + for (int i = 0; i < size; i++) { + ret[i] = ((Number) elements[i]).byteValue(); + } + return RDataFactory.createLogicalVector(ret, true); + } + if (allInteger) { + int[] ret = new int[size]; + for (int i = 0; i < size; i++) { + ret[i] = ((Number) elements[i]).intValue(); + } + return RDataFactory.createIntVector(ret, true); + } + if (allDouble) { + double[] ret = new double[size]; + for (int i = 0; i < size; i++) { + ret[i] = ((Number) elements[i]).doubleValue(); + } + return RDataFactory.createDoubleVector(ret, true); + } + if (allString) { + String[] ret = new String[size]; + for (int i = 0; i < size; i++) { + ret[i] = String.valueOf(elements[i]); + } + return RDataFactory.createStringVector(ret, true); + } + return RDataFactory.createList(elements); + } catch (UnsupportedMessageException | UnknownIdentifierException e) { + throw error(RError.Message.GENERIC, "error while converting array: " + e.getMessage()); + } + } + + @Fallback + public Object fromArray(@SuppressWarnings("unused") Object obj) { + throw error(RError.Message.GENERIC, "not a java array"); + } + } + + @ImportStatic({Message.class, RRuntime.class}) + @RBuiltin(name = ".fastr.interop.new", visibility = ON, kind = PRIMITIVE, parameterNames = {"class", "..."}, behavior = COMPLEX) + public abstract static class InteropNew extends RBuiltinNode.Arg2 { + + static { + Casts.noCasts(InteropNew.class); } @Specialization(limit = "99", guards = {"isForeignObject(clazz)", "length == args.getLength()"}) @@ -317,9 +792,10 @@ public class FastRInterop { try { Object[] argValues = new Object[args.getLength()]; for (int i = 0; i < argValues.length; i++) { - argValues[i] = toJava(args.getArgument(i)); + argValues[i] = RRuntime.r2Java(args.getArgument(i)); } - return ForeignAccess.sendNew(sendNew, clazz, argValues); + Object result = ForeignAccess.sendNew(sendNew, clazz, argValues); + return RRuntime.java2R(result); } catch (SecurityException | IllegalArgumentException | UnsupportedTypeException | ArityException | UnsupportedMessageException e) { throw error(Message.GENERIC, "error during Java object instantiation: " + e.getMessage()); } 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 89b03586643b655e1b503474f80492140cb5b475..c3de2199322aa65b8a7d6d0c9beb35aafcc30503 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 @@ -23,14 +23,20 @@ package com.oracle.truffle.r.nodes.access.vector; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives; 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.frame.VirtualFrame; 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.Message; 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; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode; @@ -41,6 +47,7 @@ import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RLogical; 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.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; @@ -48,6 +55,7 @@ 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; +@ImportStatic({RRuntime.class, com.oracle.truffle.api.interop.Message.class}) public abstract class ExtractVectorNode extends Node { protected static final int CACHE_LIMIT = 5; @@ -88,51 +96,89 @@ public abstract class ExtractVectorNode extends Node { protected abstract Object execute(VirtualFrame frame, Object vector, Object[] positions, Object exact, Object dropDimensions); - protected Node createForeignRead(Object[] positions) { - if (positions.length != 1) { - throw RError.error(this, RError.Message.GENERIC, "Invalid number positions for foreign access."); - } - return Message.READ.createNode(); - } - protected static boolean isForeignObject(TruffleObject object) { return RRuntime.isForeignObject(object); } protected static FirstStringNode createFirstString() { - return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot corce position to character for foreign access."); + return FirstStringNode.createWithError(RError.Message.GENERIC, "Cannot coerce position to character for foreign access."); } @Specialization(guards = {"isForeignObject(object)", "positions.length == cachedLength"}) protected Object accessField(TruffleObject object, Object[] positions, @SuppressWarnings("unused") Object exact, @SuppressWarnings("unused") Object dropDimensions, - @Cached("createForeignRead(positions)") Node foreignRead, + @Cached("READ.createNode()") Node foreignRead, + @Cached("KEY_INFO.createNode()") Node keyInfoNode, @Cached("positions.length") @SuppressWarnings("unused") int cachedLength, @Cached("create()") CastStringNode castNode, @Cached("createFirstString()") FirstStringNode firstString, - @Cached("createClassProfile()") ValueProfile positionProfile) { - Object position = positionProfile.profile(positions[0]); + @Cached("createClassProfile()") ValueProfile positionProfile, + @Cached("IS_NULL.createNode()") Node isNullNode, + @Cached("IS_BOXED.createNode()") Node isBoxedNode, + @Cached("UNBOX.createNode()") Node unboxNode) { + if (positions.length == 0) { + throw RError.error(this, RError.Message.GENERIC, "No positions for foreign access."); + } + positions = positionProfile.profile(positions); try { - if (position instanceof Integer) { - return ForeignAccess.send(foreignRead, object, new Object[]{((int) position) - 1}); - } else if (position instanceof Double) { - return ForeignAccess.send(foreignRead, object, new Object[]{((double) position) - 1}); - } else if (position instanceof String) { - return ForeignAccess.send(foreignRead, object, new Object[]{position}); - } else if (position instanceof RAbstractStringVector) { - String string = firstString.executeString(castNode.doCast(position)); - return ForeignAccess.send(foreignRead, object, new Object[]{string}); - } else if (position instanceof RAbstractDoubleVector) { - return ForeignAccess.send(foreignRead, object, new Object[]{((RAbstractDoubleVector) position).getDataAt(0) - 1}); - } else if (position instanceof RAbstractIntVector) { - return ForeignAccess.send(foreignRead, object, new Object[]{((RAbstractIntVector) position).getDataAt(0) - 1}); - } else { - throw RError.error(this, RError.Message.GENERIC, "invalid index during foreign access"); + try { + // TODO implicite unboxing ok? method calls seem to behave this way + Object result = object; + for (int i = 0; i < positions.length; i++) { + result = send(positions[i], foreignRead, keyInfoNode, (TruffleObject) result, firstString, castNode); + if (positions.length > 1 && i < positions.length - 1) { + assert result instanceof TruffleObject; + } + } + return unbox(result, isNullNode, isBoxedNode, unboxNode); + } catch (UnknownIdentifierException | NoSuchFieldError e) { + throw RError.interopError(RError.findParentRBase(this), e, object); } } catch (InteropException e) { throw RError.interopError(RError.findParentRBase(this), e, object); } } + private Object unbox(Object obj, Node isNullNode, Node isBoxedNode, Node unboxNode) throws UnsupportedMessageException { + if (RRuntime.isForeignObject(obj)) { + if (ForeignAccess.sendIsNull(isNullNode, (TruffleObject) obj)) { + return RNull.instance; + } + Boolean isBoxed = (Boolean) ForeignAccess.sendIsBoxed(isBoxedNode, (TruffleObject) obj); + if (isBoxed) { + return RRuntime.java2R(ForeignAccess.sendUnbox(unboxNode, (TruffleObject) obj)); + } + } + return RRuntime.java2R(obj); + } + + private Object send(Object position, Node foreignRead, Node keyInfoNode, TruffleObject object, FirstStringNode firstString, CastStringNode castNode) throws RError, InteropException { + if (position instanceof Integer) { + position = ((int) position) - 1; + } else if (position instanceof Double) { + position = ((double) position) - 1; + } else if (position instanceof RAbstractDoubleVector) { + position = ((RAbstractDoubleVector) position).getDataAt(0) - 1; + } else if (position instanceof RAbstractIntVector) { + position = ((RAbstractIntVector) position).getDataAt(0) - 1; + } else if (position instanceof RAbstractStringVector) { + position = firstString.executeString(castNode.doCast(position)); + } else if (!(position instanceof String)) { + throw RError.error(this, RError.Message.GENERIC, "invalid index during foreign access"); + } + + int info = ForeignAccess.sendKeyInfo(keyInfoNode, object, position); + if (KeyInfo.isReadable(info)) { + return ForeignAccess.sendRead(foreignRead, object, position); + } else if (position instanceof String && !KeyInfo.isExisting(info) && JavaInterop.isJavaObject(Object.class, object)) { + TruffleObject clazz = JavaInterop.toJavaClass(object); + info = ForeignAccess.sendKeyInfo(keyInfoNode, clazz, position); + if (KeyInfo.isReadable(info)) { + return ForeignAccess.sendRead(foreignRead, clazz, position); + } + } + throw RError.error(this, RError.Message.GENERIC, "invalid index/identifier during foreign access: " + position); + } + @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) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java index d85926100c32e53a126f3b83df998b5248514e6a..5c4fa8b7749708527f3d6d0b2f23354e79fe3743 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/access/vector/ReplaceVectorNode.java @@ -25,12 +25,15 @@ package com.oracle.truffle.r.nodes.access.vector; import com.oracle.truffle.api.CompilerAsserts; 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.frame.VirtualFrame; 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.Message; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.nodes.binary.BoxPrimitiveNode; import com.oracle.truffle.r.nodes.profile.TruffleBoundaryNode; @@ -38,8 +41,6 @@ import com.oracle.truffle.r.nodes.unary.CastStringNode; import com.oracle.truffle.r.nodes.unary.FirstStringNode; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RRuntime; -import com.oracle.truffle.r.runtime.data.RDouble; -import com.oracle.truffle.r.runtime.data.RInteger; import com.oracle.truffle.r.runtime.data.RTypedValue; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; @@ -49,6 +50,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; /** * Syntax node for element writes. */ +@ImportStatic({RRuntime.class, com.oracle.truffle.api.interop.Message.class}) public abstract class ReplaceVectorNode extends Node { protected static final int CACHE_LIMIT = 5; @@ -97,40 +99,50 @@ public abstract class ReplaceVectorNode extends Node { @Specialization(guards = {"isForeignObject(object)", "positions.length == cachedLength"}) protected Object accessField(TruffleObject object, Object[] positions, Object value, - @Cached("createForeignWrite(positions)") Node foreignRead, + @Cached("WRITE.createNode()") Node foreignWrite, + @Cached("KEY_INFO.createNode()") Node keyInfo, @SuppressWarnings("unused") @Cached("positions.length") int cachedLength, @Cached("create()") CastStringNode castNode, @Cached("createFirstString()") FirstStringNode firstString) { - - Object writtenValue = value; - if (writtenValue instanceof RInteger) { - writtenValue = ((RInteger) writtenValue).getValue(); - } else if (writtenValue instanceof RDouble) { - writtenValue = ((RDouble) writtenValue).getValue(); - } + Object writtenValue = RRuntime.r2Java(value); Object position = positions[0]; try { - if (position instanceof Integer) { - return ForeignAccess.send(foreignRead, object, new Object[]{((Integer) position) - 1, writtenValue}); - } else if (position instanceof Double) { - return ForeignAccess.send(foreignRead, object, new Object[]{((Double) position) - 1, writtenValue}); - } else if (position instanceof String) { - return ForeignAccess.send(foreignRead, object, new Object[]{position, writtenValue}); - } else if (position instanceof RAbstractStringVector) { - String string = firstString.executeString(castNode.doCast(position)); - return ForeignAccess.send(foreignRead, object, new Object[]{string, writtenValue}); - } else if (position instanceof RAbstractDoubleVector) { - return ForeignAccess.send(foreignRead, object, new Object[]{((RAbstractDoubleVector) position).getDataAt(0) - 1, writtenValue}); - } else if (position instanceof RAbstractIntVector) { - return ForeignAccess.send(foreignRead, object, new Object[]{((RAbstractIntVector) position).getDataAt(0) - 1, writtenValue}); - } else { - throw RError.error(this, RError.Message.GENERIC, "invalid index during foreign access"); - } + return write(position, foreignWrite, keyInfo, object, writtenValue, firstString, castNode); } catch (InteropException e) { throw RError.interopError(RError.findParentRBase(this), e, object); } } + private Object write(Object position, Node foreignWrite, Node keyInfoNode, TruffleObject object, Object writtenValue, FirstStringNode firstString, CastStringNode castNode) + throws InteropException, RError { + if (position instanceof Integer) { + position = ((Integer) position) - 1; + } else if (position instanceof Double) { + position = ((Double) position) - 1; + } else if (position instanceof RAbstractDoubleVector) { + position = ((RAbstractDoubleVector) position).getDataAt(0) - 1; + } else if (position instanceof RAbstractIntVector) { + position = ((RAbstractIntVector) position).getDataAt(0) - 1; + } else if (position instanceof RAbstractStringVector) { + String string = firstString.executeString(castNode.doCast(position)); + position = string; + } else if (!(position instanceof String)) { + throw RError.error(this, RError.Message.GENERIC, "invalid index during foreign access"); + } + + int info = ForeignAccess.sendKeyInfo(keyInfoNode, object, position); + if (KeyInfo.isWritable(info)) { + return ForeignAccess.sendWrite(foreignWrite, object, position, writtenValue); + } else if (position instanceof String && !KeyInfo.isExisting(info) && JavaInterop.isJavaObject(Object.class, object)) { + TruffleObject clazz = JavaInterop.toJavaClass(object); + info = ForeignAccess.sendKeyInfo(keyInfoNode, clazz, position); + if (KeyInfo.isWritable(info)) { + return ForeignAccess.sendWrite(foreignWrite, clazz, position, writtenValue); + } + } + throw RError.error(this, RError.Message.GENERIC, "invalid index/identifier during foreign access: " + position); + } + @Specialization(limit = "CACHE_LIMIT", guards = {"cached != null", "cached.isSupported(vector, positions)"}) protected Object doRecursive(VirtualFrame frame, RAbstractListVector vector, Object[] positions, Object value, // @Cached("createRecursiveCache(vector, positions)") RecursiveReplaceSubscriptNode cached) { diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java index fd54fa745ced5ad26aa9bd395633daf504cccdab..29c1453ada068b616d66acff9b7c3d097a92095e 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/ClassHierarchyNode.java @@ -48,6 +48,7 @@ import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RInteropScalar; import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -148,6 +149,11 @@ public abstract class ClassHierarchyNode extends UnaryNode { return withImplicitTypes ? ImplicitClassHierarchyNode.getImplicitClass(RType.Null) : null; } + @Specialization + protected RStringVector getClassHr(@SuppressWarnings("unused") RInteropScalar arg) { + return withImplicitTypes ? ImplicitClassHierarchyNode.getImplicitClass(arg.getRType()) : null; + } + @Specialization protected RStringVector getClassHr(@SuppressWarnings("unused") REmpty arg) { return withImplicitTypes ? ImplicitClassHierarchyNode.getImplicitClass(RType.Null) : null; diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java index a2bf334242b3b14374d164e4cd87b2b71089bc7a..7fa4270828d46489c5babae16b4f34a4715714db 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/function/RCallNode.java @@ -40,9 +40,12 @@ import com.oracle.truffle.api.frame.FrameSlot; import com.oracle.truffle.api.frame.FrameSlotTypeException; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.ArityException; import com.oracle.truffle.api.interop.ForeignAccess; import com.oracle.truffle.api.interop.Message; 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.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeCost; @@ -90,6 +93,7 @@ import com.oracle.truffle.r.runtime.data.REmpty; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RMissing; +import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.RPromise.Closure; import com.oracle.truffle.r.runtime.data.RStringVector; @@ -526,6 +530,7 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS @Child private CallArgumentsNode arguments; @Child private Node foreignCall; + @Child private Node isNullCall; @CompilationFinal private int foreignCallArgCount; public ForeignCall(CallArgumentsNode arguments) { @@ -540,15 +545,20 @@ public abstract class RCallNode extends RCallBaseNode implements RSyntaxNode, RS foreignCallArgCount = argumentsArray.length; } try { - Object result = ForeignAccess.sendExecute(foreignCall, function, argumentsArray); - if (result instanceof Boolean) { - // convert to R logical - // TODO byte/short convert to int? - result = RRuntime.asLogical((boolean) result); + Object result = ForeignAccess.sendExecute(foreignCall, function, RRuntime.r2Java(argumentsArray)); + if (RRuntime.isForeignObject(result)) { + if (isNullCall == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + isNullCall = insert(Message.IS_NULL.createNode()); + } + if (ForeignAccess.sendIsNull(isNullCall, (TruffleObject) result)) { + return RNull.instance; + } } - return result; - } catch (Throwable e) { + return RRuntime.java2R(result); + } catch (ArityException | UnsupportedMessageException | UnsupportedTypeException e) { CompilerDirectives.transferToInterpreter(); + RInternalError.reportError(e); throw RError.interopError(RError.findParentRBase(this), e, function); } } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java index 5b442a98d5ac425061188d43edf3216253232f8f..2ea4c2b07e10e2b1091fda964087e9e2ba77f6cc 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/CastListNode.java @@ -26,6 +26,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.r.nodes.attributes.ArrayAttributeNode; @@ -37,6 +38,7 @@ import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RFunction; +import com.oracle.truffle.r.runtime.data.RInteropScalar; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RNull; @@ -147,6 +149,16 @@ public abstract class CastListNode extends CastBaseNode { return RDataFactory.createList(new Object[]{s}); } + @Specialization + protected RList doRInterop(RInteropScalar ri) { + return RDataFactory.createList(new Object[]{ri}); + } + + @Specialization(guards = {"isForeignObject(to)"}) + protected RList doForeignObject(TruffleObject to) { + return RDataFactory.createList(new Object[]{to}); + } + public static CastListNode create() { return CastListNodeGen.create(true, true, true); } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/PrecedenceNode.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/PrecedenceNode.java index 03eda37330086b211fb655eaf8f39044fd8860df..1d8a29e9d0177c5ed84f70955de8b0cf4fa606e6 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/PrecedenceNode.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/unary/PrecedenceNode.java @@ -25,6 +25,7 @@ package com.oracle.truffle.r.nodes.unary; 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.interop.TruffleObject; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RComplex; @@ -35,6 +36,7 @@ import com.oracle.truffle.r.runtime.data.RExpression; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RIntSequence; import com.oracle.truffle.r.runtime.data.RIntVector; +import com.oracle.truffle.r.runtime.data.RInteropScalar; import com.oracle.truffle.r.runtime.data.RLanguage; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RLogicalVector; @@ -151,6 +153,11 @@ public abstract class PrecedenceNode extends RBaseNode { return LIST_PRECEDENCE; } + @Specialization + protected int doRInteroptFloat(RInterop b, boolean recursive) { + return NO_PRECEDENCE; + } + @Specialization(guards = "recursive") protected int doListRecursive(RList val, boolean recursive, @Cached("createRecursive()") PrecedenceNode precedenceNode) { @@ -205,6 +212,16 @@ public abstract class PrecedenceNode extends RBaseNode { return LIST_PRECEDENCE; } + @Specialization + protected int doRInterop(RInteropScalar ri, boolean recursive) { + return LIST_PRECEDENCE; + } + + @Specialization(guards = {"isForeignObject(to)"}) + protected int doForeignObject(TruffleObject to, boolean recursive) { + return LIST_PRECEDENCE; + } + @Specialization(guards = {"!recursive", "args.getLength() == 1"}) protected int doArgsValuesAndNames(RArgsValuesAndNames args, boolean recursive, @Cached("createRecursive()") PrecedenceNode precedenceNode) { 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 8583792a6fa9bac94b31a98244a5b83cacf22be6..fbb3953558a93d1e1a604db5ce01d7ce14dc455e 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 @@ -613,6 +613,7 @@ public final class RError extends RuntimeException { UNRECOGNIZED_FORMAT("unrecognized format specification '%s'"), INVALID_FORMAT_LOGICAL("invalid format '%s'; use format %%d or %%i for logical objects"), INVALID_FORMAT_INTEGER("invalid format '%s'; use format %%d, %%i, %%o, %%x or %%X for integer objects"), + POS_NOT_ALLOWED_WITH_NUMERIC("pos argument not allowed with a numeric value"), // the following list is incomplete (but like GNU-R) INVALID_FORMAT_DOUBLE("invalid format '%s'; use format %%f, %%e, %%g or %%a for numeric objects"), INVALID_LOGICAL("'%s' must be TRUE or FALSE"), diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java index 542a7976db4d7acd2514abdc426bad713a626cd0..d80fe43d1b3578985e0c98a8257f844cbd4db456 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RRuntime.java @@ -21,22 +21,31 @@ import com.oracle.truffle.api.frame.FrameSlotKind; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.java.JavaInterop; import com.oracle.truffle.r.runtime.data.RComplex; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDouble; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RInteger; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropByte; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropChar; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropFloat; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropLong; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropShort; import com.oracle.truffle.r.runtime.data.RLogical; +import com.oracle.truffle.r.runtime.data.RNull; import com.oracle.truffle.r.runtime.data.RRaw; import com.oracle.truffle.r.runtime.data.RString; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.data.RSymbol; 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.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector; import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector; 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; import com.oracle.truffle.r.runtime.data.model.RAbstractVector; import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor; @@ -312,7 +321,7 @@ public class RRuntime { } public static String logicalToStringNoCheck(byte operand) { - assert operand == LOGICAL_TRUE || operand == LOGICAL_FALSE; + assert operand == LOGICAL_TRUE || operand == LOGICAL_FALSE : "operand: " + operand; return operand == LOGICAL_TRUE ? STRING_TRUE : STRING_FALSE; } @@ -918,4 +927,66 @@ public class RRuntime { return xa.hasDimensions(); } + public static Object java2R(Object obj) { + if (obj == null) { + obj = RNull.instance; + } else if (obj instanceof Boolean) { + obj = RRuntime.asLogical((boolean) obj); + } else if (obj instanceof Byte) { + obj = ((Byte) obj).intValue(); + } else if (obj instanceof Short) { + obj = ((Short) obj).intValue(); + } else if (obj instanceof Long) { + obj = (((Long) obj).doubleValue()); + } else if (obj instanceof Float) { + obj = (((Float) obj).doubleValue()); + } else if (obj instanceof Character) { + obj = ((Character) obj).toString(); + } + return obj; + } + + public static Object[] r2Java(Object[] objects) { + Object[] ret = new Object[objects.length]; + for (int i = 0; i < objects.length; i++) { + ret[i] = RRuntime.r2Java(objects[i]); + } + return ret; + } + + public static Object r2Java(Object obj) { + if (obj == RNull.instance) { + return JavaInterop.asTruffleObject(null); + } else if (obj instanceof Byte) { + return RRuntime.fromLogical((byte) obj); + } else if (obj instanceof RInteropByte) { + return ((RInteropByte) obj).getValue(); + } else if (obj instanceof RInteropChar) { + return ((RInteropChar) obj).getValue(); + } else if (obj instanceof RInteropFloat) { + return ((RInteropFloat) obj).getValue(); + } else if (obj instanceof RInteropLong) { + return ((RInteropLong) obj).getValue(); + } else if (obj instanceof RInteropShort) { + return ((RInteropShort) obj).getValue(); + } else if (obj instanceof RAbstractAtomicVector && ((RAbstractAtomicVector) obj).getLength() == 1) { + if (obj instanceof RAbstractDoubleVector) { + RAbstractDoubleVector v = (RAbstractDoubleVector) obj; + return v.getDataAt(0); + } else if (obj instanceof RAbstractIntVector) { + RAbstractIntVector v = (RAbstractIntVector) obj; + return v.getDataAt(0); + } else if (obj instanceof RAbstractLogicalVector) { + RAbstractLogicalVector v = (RAbstractLogicalVector) obj; + return v.getDataAt(0) == RRuntime.LOGICAL_TRUE; + } else if (obj instanceof RAbstractRawVector) { + RAbstractRawVector v = (RAbstractRawVector) obj; + return v.getDataAt(0).getValue(); + } else if (obj instanceof RAbstractStringVector) { + RAbstractStringVector v = (RAbstractStringVector) obj; + return v.getDataAt(0); + } + } + return obj; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java index ddf2a1e6c0cd6cfec7d8c887631006d9cb63978f..c4d03652bf2589339d29122b77bc67cd6709bc7d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RType.java @@ -47,7 +47,12 @@ public enum RType { S4Object("S4", -1), Connection("connection", -1), Dots("...", -1), - TruffleObject("truffle.object", -1); + TruffleObject("truffle.object", -1), + RInteropByte("interopt.byte", -1), + RInteropChar("interopt.char", -1), + RInteropFloat("interopt.float", -1), + RInteropLong("interopt.long", -1), + RInteropShort("interopt.short", -1); public static final int NO_PRECEDENCE = -1; public static final int NUMBER_OF_PRECEDENCES = 9; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteropScalar.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteropScalar.java new file mode 100644 index 0000000000000000000000000000000000000000..e2f4a3bc4f353262e1549262b330a0cba60497e6 --- /dev/null +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RInteropScalar.java @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2013, 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 + * 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.runtime.data; + +import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.CompilerDirectives.ValueType; +import com.oracle.truffle.r.runtime.RType; + +@ValueType +public abstract class RInteropScalar extends RScalar { + + public abstract Object getRValue(); + + @ValueType + public static final class RInteropByte extends RInteropScalar { + + private final byte value; + + private RInteropByte(byte value) { + this.value = value; + } + + public static RInteropByte valueOf(byte value) { + return new RInteropByte(value); + } + + public byte getValue() { + return value; + } + + @Override + public Object getRValue() { + return ((Byte) value).intValue(); + } + + @Override + public RType getRType() { + return RType.RInteropByte; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return Byte.toString(value); + } + } + + @ValueType + public static final class RInteropChar extends RInteropScalar { + + private final char value; + + private RInteropChar(char value) { + this.value = value; + } + + public static RInteropChar valueOf(char value) { + return new RInteropChar(value); + } + + public char getValue() { + return value; + } + + @Override + public Object getRValue() { + return Character.toString(value); + } + + @Override + public RType getRType() { + return RType.RInteropChar; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return Character.toString(value); + } + } + + @ValueType + public static final class RInteropFloat extends RInteropScalar { + + private final float value; + + private RInteropFloat(float value) { + this.value = value; + } + + public static RInteropFloat valueOf(float value) { + return new RInteropFloat(value); + } + + public float getValue() { + return value; + } + + @Override + public Object getRValue() { + return ((Float) value).doubleValue(); + } + + @Override + public RType getRType() { + return RType.RInteropFloat; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return Float.toString(value); + } + } + + @ValueType + public static final class RInteropLong extends RInteropScalar { + + private final long value; + + private RInteropLong(long value) { + this.value = value; + } + + public static RInteropLong valueOf(long value) { + return new RInteropLong(value); + } + + public long getValue() { + return value; + } + + @Override + public Object getRValue() { + return ((Long) value).doubleValue(); + } + + @Override + public RType getRType() { + return RType.RInteropLong; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return Long.toString(value); + } + } + + @ValueType + public static final class RInteropShort extends RInteropScalar { + + private final short value; + + private RInteropShort(short value) { + this.value = value; + } + + public static RInteropShort valueOf(short value) { + return new RInteropShort(value); + } + + public short getValue() { + return value; + } + + @Override + public Object getRValue() { + return ((Short) value).intValue(); + } + + @Override + public RType getRType() { + return RType.RInteropShort; + } + + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return Short.toString(value); + } + + } +} diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java index c7c9a3819d8f46b22196331fdc85c3c590d8f6d0..f11da3d123650f52a9ed9c974c93284153ae10de 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RTypes.java @@ -26,6 +26,11 @@ import com.oracle.truffle.api.dsl.ImplicitCast; import com.oracle.truffle.api.dsl.TypeCast; import com.oracle.truffle.api.dsl.TypeCheck; import com.oracle.truffle.api.dsl.TypeSystem; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropByte; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropChar; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropFloat; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropLong; +import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropShort; import com.oracle.truffle.r.runtime.data.model.RAbstractAtomicVector; import com.oracle.truffle.r.runtime.data.model.RAbstractComplexVector; import com.oracle.truffle.r.runtime.data.model.RAbstractContainer; @@ -47,7 +52,11 @@ import com.oracle.truffle.r.runtime.nodes.RNode; * @see RNode */ @TypeSystem({ - byte.class, RAbstractLogicalVector.class, + byte.class, RAbstractLogicalVector.class, RInteropByte.class, + RInteropChar.class, + RInteropFloat.class, + RInteropLong.class, + RInteropShort.class, int.class, RAbstractIntVector.class, double.class, RAbstractDoubleVector.class, String.class, RAbstractStringVector.class, 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 384d1e505657731303dbe9c0856e379eebf748d0..23d2b3fefd7c2bfffbf65118820ea631da1b5eb9 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 @@ -130560,6 +130560,606 @@ attr(,"is.truffle.object") attr(,"is.truffle.object") [1] TRUE +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testAllTypes# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "true127a32767214748364792233720368547758071.7976931348623157E3083.4028235E38testString" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$allTypesMethod(TRUE,127,"a",32767,2147483647,9223372036854775807,1.7976931348623157E308,3.4028235E38,"testString") } +[1] "true127a32767214748364792233720368547758071.7976931348623157E3083.4028235E38testString" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testAllTypes# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "true127a32767214748364792233720368547758071.7976931348623157E3083.4028235E38testString" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$allTypesStaticMethod(TRUE,127,"a",32767,2147483647,9223372036854775807,1.7976931348623157E308,3.4028235E38,"testString") } +[1] "true127a32767214748364792233720368547758071.7976931348623157E3083.4028235E38testString" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a string" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticStringObject } +[1] "a string" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a string" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStringObject } +[1] "a string" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldChar } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldCharObject } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticChar } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticCharObject } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.7976931348623157E308 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldDouble } +[1] 1.797693e+308 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.7976931348623157E308 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldDoubleObject } +[1] 1.797693e+308 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.7976931348623157E308 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticDouble } +[1] 1.797693e+308 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.7976931348623157E308 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticDoubleObject } +[1] 1.797693e+308 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldByte } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldByteObject } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticByte } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticByteObject } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldInteger } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldIntegerObject } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticInteger } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticIntegerObject } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldFloat } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldFloatObject } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticFloat } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticFloatObject } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldShort } +[1] 32767 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldShortObject } +[1] 32767 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticShort } +[1] 32767 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticShortObject } +[1] 32767 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldLong } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldLongObject } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticLong } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticLongObject } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { NULL } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldNullObject } +NULL + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { NULL } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticNullObject } +NULL + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { NaN } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticNaN } +[1] NaN + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { NaN } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticNaNObject } +[1] NaN + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldBoolean } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldBooleanObject } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticBoolean } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticBooleanObject } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] "a" "b" "c"\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticStringArray } +[1] "a" "b" "c" +attr(,"is.truffle.object") +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] "a" "b" "c"\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStringArray } +[1] "a" "b" "c" +attr(,"is.truffle.object") +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] 1 2 3\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldIntArray } +[1] 1 2 3 +attr(,"is.truffle.object") +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testFields# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] 1 2 3\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$fieldStaticIntArray } +[1] 1 2 3 +attr(,"is.truffle.object") +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a string" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticStringObject() } +[1] "a string" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a string" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStringObject() } +[1] "a string" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodChar() } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodCharObject() } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticChar() } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { "a" } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticCharObject() } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.7976931348623157E308 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodDouble() } +[1] 1.797693e+308 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.7976931348623157E308 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodDoubleObject() } +[1] 1.797693e+308 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.7976931348623157E308 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticDouble() } +[1] 1.797693e+308 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.7976931348623157E308 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticDoubleObject() } +[1] 1.797693e+308 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodByte() } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodByteObject() } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticByte() } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticByteObject() } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodInteger() } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodIntegerObject() } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticInteger() } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticIntegerObject() } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodFloat() } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodFloatObject() } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticFloat() } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticFloatObject() } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodShort() } +[1] 32767 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodShortObject() } +[1] 32767 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticShort() } +[1] 32767 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticShortObject() } +[1] 32767 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodLong() } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodLongObject() } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticLong() } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticLongObject() } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { NULL } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodReturnsNull() } +NULL + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { NULL } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticReturnsNull() } +NULL + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodBoolean() } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodBooleanObject() } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticBoolean() } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticBooleanObject() } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] "a" "b" "c"\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticStringArray() } +[1] "a" "b" "c" +attr(,"is.truffle.object") +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] "a" "b" "c"\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStringArray() } +[1] "a" "b" "c" +attr(,"is.truffle.object") +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] 1 2 3\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodIntArray() } +[1] 1 2 3 +attr(,"is.truffle.object") +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testMethods# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] 1 2 3\nattr(,"is.truffle.object")\n[1] TRUE\n') } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$methodStaticIntArray() } +[1] 1 2 3 +attr(,"is.truffle.object") +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'a' } else { tc <- .fastr.java.class('java.lang.Character'); t <- .fastr.interop.new(tc, .fastr.interop.toChar(97)); t } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'abc' } else { tc <- .fastr.java.class('java.lang.String'); t <- .fastr.interop.new(tc, 'abc'); t } +[1] "abc" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'truffle.object' } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestNullClass'); t <- .fastr.interop.new(tc, NULL); class(t) } +[1] "truffle.object" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { tc <- .fastr.java.class('java.lang.Byte'); t <- .fastr.interop.new(tc, .fastr.interop.toByte(1)); t } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { tc <- .fastr.java.class('java.lang.Integer'); t <- .fastr.interop.new(tc, 1L); t } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { tc <- .fastr.java.class('java.lang.Long'); t <- .fastr.interop.new(tc, .fastr.interop.toLong(1)); t } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { tc <- .fastr.java.class('java.lang.Short'); t <- .fastr.interop.new(tc, .fastr.interop.toShort(1)); t } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.1 } else { tc <- .fastr.java.class('java.lang.Double'); t <- .fastr.interop.new(tc, 1.1); t } +[1] 1.1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.1 } else { tc <- .fastr.java.class('java.lang.Float'); t <- .fastr.interop.new(tc, .fastr.interop.toFloat(1.1)); t } +[1] 1.1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNew# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('java.lang.Boolean'); t <- .fastr.interop.new(tc, TRUE); t } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNonPrimitiveParameter# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { TRUE } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$equals(t) } +[1] TRUE + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNullParameter#Ignored.Unimplemented# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { java.lang.Long } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$isNull(1) } +Error: object 'java.lang.Long' not found + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testNullParameter#Ignored.Unimplemented# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { java.lang.String } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$isNull('string') } +Error: object 'java.lang.String' not found + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testOverloaded#Ignored.Unimplemented# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { boolean } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$isOverloaded(TRUE) } +Error: object 'boolean' not found + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testOverloaded#Ignored.Unimplemented# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { java.lang.String } else { tc <- .fastr.java.class('com.oracle.truffle.r.test.library.fastr.TestJavaInterop$TestClass'); t <- .fastr.interop.new(tc); t$isOverloaded('string') } +Error: object 'java.lang.String' not found + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.byte' } else { v <- .fastr.interop.toByte(1.1); class(v); } +[1] "interopt.byte" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.byte' } else { v <- .fastr.interop.toByte(1.1); typeof(v); } +[1] "interopt.byte" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { -1 } else { v <- .fastr.interop.toByte(1.7976931348623157E308); v; } +[1] -1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { -1 } else { v <- .fastr.interop.toByte(2147483647); v; } +[1] -1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { -128 } else { v <- .fastr.interop.toByte(-128); v; } +[1] -128 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 0 } else { v <- .fastr.interop.toByte(-2147483648); v; } +[1] 0 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 0 } else { v <- .fastr.interop.toByte(4.9E-324); v; } +[1] 0 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toByte(1); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toByte(1.1); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toByte(as.raw(1)); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToByte# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 127 } else { v <- .fastr.interop.toByte(127); v; } +[1] 127 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToChar# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'a' } else { v <- .fastr.interop.toChar('a'); v; } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToChar# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'a' } else { v <- .fastr.interop.toChar(97); v; } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToChar# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'a' } else { v <- .fastr.interop.toChar(97.1); v; } +[1] "a" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToChar# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'b' } else { v <- .fastr.interop.toChar('abc', 1); v; } +[1] "b" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToChar# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'b' } else { v <- .fastr.interop.toChar('abc', 1.1); v; } +[1] "b" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToChar# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.char' } else { v <- .fastr.interop.toChar(97); class(v); } +[1] "interopt.char" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToChar# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.char' } else { v <- .fastr.interop.toChar(97); typeof(v); } +[1] "interopt.char" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.float' } else { v <- .fastr.interop.toFloat(1.1); class(v); } +[1] "interopt.float" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.float' } else { v <- .fastr.interop.toFloat(1.1); typeof(v); } +[1] "interopt.float" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 0.0 } else { v <- .fastr.interop.toFloat(4.9E-324); v; } +[1] 0 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toFloat(1); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toFloat(as.raw(1)); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.1 } else { v <- .fastr.interop.toFloat(1.1); v; } +[1] 1.1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1.401298464324817E-45 } else { v <- .fastr.interop.toFloat(1.4E-45); v; } +[1] 1.401298e-45 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 3.4028235E38 } else { v <- .fastr.interop.toFloat(3.4028235E38); v; } +[1] 3.402823e+38 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToFloat# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { Inf } else { v <- .fastr.interop.toFloat(1.7976931348623157E308); v; } +[1] Inf + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.long' } else { v <- .fastr.interop.toLong(1.1); class(v); } +[1] "interopt.long" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.long' } else { v <- .fastr.interop.toLong(1.1); typeof(v); } +[1] "interopt.long" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { -2147483648 } else { v <- .fastr.interop.toLong(-2147483648); v; } +[1] -2147483648 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 0 } else { v <- .fastr.interop.toLong(4.9E-324); v; } +[1] 0 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toLong(1); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toLong(1.1); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toLong(as.raw(1)); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 2147483647 } else { v <- .fastr.interop.toLong(2147483647); v; } +[1] 2147483647 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToLong# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 9223372036854775807 } else { v <- .fastr.interop.toLong(1.7976931348623157E308); v; } +[1] 9.223372e+18 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.short' } else { v <- .fastr.interop.toShort(1.1); class(v); } +[1] "interopt.short" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 'interopt.short' } else { v <- .fastr.interop.toShort(1.1); typeof(v); } +[1] "interopt.short" + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { -1 } else { v <- .fastr.interop.toShort(1.7976931348623157E308); v; } +[1] -1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { -1 } else { v <- .fastr.interop.toShort(2147483647); v; } +[1] -1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { -32768 } else { v <- .fastr.interop.toShort(-32768); v; } +[1] -32768 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 0 } else { v <- .fastr.interop.toShort(-2147483648); v; } +[1] 0 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 0 } else { v <- .fastr.interop.toShort(4.9E-324); v; } +[1] 0 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toShort(1); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toShort(1.1); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { v <- .fastr.interop.toShort(as.raw(1)); v; } +[1] 1 + +##com.oracle.truffle.r.test.library.fastr.TestJavaInterop.testToShort# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { 32767 } else { v <- .fastr.interop.toShort(32767); v; } +[1] 32767 + ##com.oracle.truffle.r.test.library.fastr.TestStateTrans.testTransitions# #if (length(grep("FastR", R.Version()$version.string)) != 1) { 1 } else { { f<-function(x) .fastr.refcountinfo(x); f(c(1,2)) } } [1] 1 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java index 21d6e39b32118f9e58899eee2962eff22cb8e6ad..1eb1faf9b642b24dbb7711d5c867c97feea8e5bc 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/TestBase.java @@ -49,6 +49,7 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextKind; import com.oracle.truffle.r.test.generate.FastRSession; import com.oracle.truffle.r.test.generate.GnuROneShotRSession; import com.oracle.truffle.r.test.generate.TestOutputManager; +import java.io.OutputStream; /** * Base class for all unit tests. The unit tests are actually arranged as a collection of @@ -469,8 +470,16 @@ public class TestBase { } // support testing of FastR-only functionality (equivalent GNU R output provided separately) + protected void assertEvalFastR(TestTrait trait1, String input, String gnuROutput) { + evalAndCompare(getAssertEvalFastR(gnuROutput, input), trait1); + } + protected void assertEvalFastR(String input, String gnuROutput) { - evalAndCompare(new String[]{"if (length(grep(\"FastR\", R.Version()$version.string)) != 1) { " + gnuROutput + " } else { " + input + " }"}); + evalAndCompare(getAssertEvalFastR(gnuROutput, input)); + } + + private static String[] getAssertEvalFastR(String gnuROutput, String input) { + return new String[]{"if (length(grep(\"FastR\", R.Version()$version.string)) != 1) { " + gnuROutput + " } else { " + input + " }"}; } /* 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 new file mode 100644 index 0000000000000000000000000000000000000000..22d14b31b44934768f4dcc9d5283193f23c15c02 --- /dev/null +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java @@ -0,0 +1,595 @@ +/* + * 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 + * 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.test.library.fastr; + +import com.oracle.truffle.r.runtime.RType; +import org.junit.Test; + +import com.oracle.truffle.r.test.TestBase; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class TestJavaInterop extends TestBase { + + private static final String TEST_CLASS = TestClass.class.getName(); + + @Test + public void testToByte() { + assertEvalFastR("v <- .fastr.interop.toByte(1L); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toByte(1.1); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toByte(as.raw(1)); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toByte(1.1); class(v);", "'" + RType.RInteropByte.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toByte(1.1); typeof(v);", "'" + RType.RInteropByte.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toByte(" + Byte.MAX_VALUE + "); v;", "" + Byte.MAX_VALUE); + assertEvalFastR("v <- .fastr.interop.toByte(" + Byte.MIN_VALUE + "); v;", "" + Byte.MIN_VALUE); + assertEvalFastR("v <- .fastr.interop.toByte(" + Integer.MAX_VALUE + "); v;", "" + new Integer(Integer.MAX_VALUE).byteValue()); + assertEvalFastR("v <- .fastr.interop.toByte(" + Integer.MIN_VALUE + "); v;", "" + new Integer(Integer.MIN_VALUE).byteValue()); + assertEvalFastR("v <- .fastr.interop.toByte(" + Double.MAX_VALUE + "); v;", "" + new Double(Double.MAX_VALUE).byteValue()); + assertEvalFastR("v <- .fastr.interop.toByte(" + Double.MIN_VALUE + "); v;", "" + new Double(Double.MIN_VALUE).byteValue()); + } + + @Test + public void testToFloat() { + assertEvalFastR("v <- .fastr.interop.toFloat(1L); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toFloat(1.1); v;", "1.1"); + assertEvalFastR("v <- .fastr.interop.toFloat(as.raw(1)); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toFloat(1.1); class(v);", "'" + RType.RInteropFloat.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toFloat(1.1); typeof(v);", "'" + RType.RInteropFloat.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toFloat(1L); class(v);", "'" + RType.RInteropFloat.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toFloat(1L); typeof(v);", "'" + RType.RInteropFloat.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toFloat(" + Float.MAX_VALUE + "); v;", "" + Float.MAX_VALUE); + assertEvalFastR("v <- .fastr.interop.toFloat(" + Float.MIN_VALUE + "); v;", "" + (double) Float.MIN_VALUE); + assertEvalFastR("v <- .fastr.interop.toFloat(" + Double.MAX_VALUE + "); v;", "Inf"); + assertEvalFastR("v <- .fastr.interop.toFloat(" + Double.MIN_VALUE + "); v;", "" + new Double(Double.MIN_VALUE).floatValue()); + } + + @Test + public void testToLong() { + assertEvalFastR("v <- .fastr.interop.toLong(1L); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toLong(1.1); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toLong(as.raw(1)); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toLong(1.1); class(v);", "'" + RType.RInteropLong.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toLong(1.1); typeof(v);", "'" + RType.RInteropLong.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toLong(1L); class(v);", "'" + RType.RInteropLong.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toLong(1L); typeof(v);", "'" + RType.RInteropLong.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toLong(" + Integer.MAX_VALUE + "); v;", "" + Integer.MAX_VALUE); + assertEvalFastR("v <- .fastr.interop.toLong(" + Integer.MIN_VALUE + "); v;", "" + Integer.MIN_VALUE); + assertEvalFastR("v <- .fastr.interop.toLong(" + Double.MAX_VALUE + "); v;", "" + new Double(Double.MAX_VALUE).longValue()); + assertEvalFastR("v <- .fastr.interop.toLong(" + Double.MIN_VALUE + "); v;", "" + new Double(Double.MIN_VALUE).longValue()); + } + + @Test + public void testToShort() { + assertEvalFastR("v <- .fastr.interop.toShort(1L); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toShort(1.1); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toShort(as.raw(1)); v;", "1"); + assertEvalFastR("v <- .fastr.interop.toShort(1.1); class(v);", "'" + RType.RInteropShort.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toShort(1.1); typeof(v);", "'" + RType.RInteropShort.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toShort(1L); class(v);", "'" + RType.RInteropShort.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toShort(1L); typeof(v);", "'" + RType.RInteropShort.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toShort(" + Short.MAX_VALUE + "); v;", "" + Short.MAX_VALUE); + assertEvalFastR("v <- .fastr.interop.toShort(" + Short.MIN_VALUE + "); v;", "" + Short.MIN_VALUE); + assertEvalFastR("v <- .fastr.interop.toShort(" + Integer.MAX_VALUE + "); v;", "" + new Integer(Integer.MAX_VALUE).shortValue()); + assertEvalFastR("v <- .fastr.interop.toShort(" + Integer.MIN_VALUE + "); v;", "" + new Integer(Integer.MIN_VALUE).shortValue()); + assertEvalFastR("v <- .fastr.interop.toShort(" + Double.MAX_VALUE + "); v;", "" + new Double(Double.MAX_VALUE).shortValue()); + assertEvalFastR("v <- .fastr.interop.toShort(" + Double.MIN_VALUE + "); v;", "" + new Double(Double.MIN_VALUE).shortValue()); + } + + @Test + public void testToChar() { + assertEvalFastR("v <- .fastr.interop.toChar(97L); v;", "'a'"); + assertEvalFastR("v <- .fastr.interop.toChar(97.1); v;", "'a'"); + assertEvalFastR("v <- .fastr.interop.toChar(97.1, 1); v;", "cat('Error in .fastr.interop.toChar(97.1, 1) : ', '\n', ' pos argument not allowed with a numeric value', '\n')"); + assertEvalFastR("v <- .fastr.interop.toChar(97L, 1); v;", "cat('Error in .fastr.interop.toChar(97L, 1) : ','\n',' pos argument not allowed with a numeric value', '\n')"); + assertEvalFastR("v <- .fastr.interop.toChar('abc', 1); v;", "'b'"); + assertEvalFastR("v <- .fastr.interop.toChar('abc', 1.1); v;", "'b'"); + assertEvalFastR("v <- .fastr.interop.toChar(97.1); class(v);", "'" + RType.RInteropChar.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toChar(97.1); typeof(v);", "'" + RType.RInteropChar.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toChar(97L); class(v);", "'" + RType.RInteropChar.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toChar(97L); typeof(v);", "'" + RType.RInteropChar.getName() + "'"); + assertEvalFastR("v <- .fastr.interop.toChar('a'); v;", "'a'"); + } + + @Test + public void testNew() { + assertEvalFastR("tc <- .fastr.java.class('" + Boolean.class.getName() + "'); t <- .fastr.interop.new(tc, TRUE); t", "TRUE"); + assertEvalFastR("tc <- .fastr.java.class('" + Byte.class.getName() + "'); t <- .fastr.interop.new(tc, .fastr.interop.toByte(1)); t", "1"); + assertEvalFastR("tc <- .fastr.java.class('" + Character.class.getName() + "'); t <- .fastr.interop.new(tc, .fastr.interop.toChar(97)); t", "'a'"); + assertEvalFastR("tc <- .fastr.java.class('" + Double.class.getName() + "'); t <- .fastr.interop.new(tc, 1.1); t", "1.1"); + assertEvalFastR("tc <- .fastr.java.class('" + Float.class.getName() + "'); t <- .fastr.interop.new(tc, .fastr.interop.toFloat(1.1)); t", "1.1"); + assertEvalFastR("tc <- .fastr.java.class('" + Integer.class.getName() + "'); t <- .fastr.interop.new(tc, 1L); t", "1"); + assertEvalFastR("tc <- .fastr.java.class('" + Long.class.getName() + "'); t <- .fastr.interop.new(tc, .fastr.interop.toLong(1)); t", "1"); + assertEvalFastR("tc <- .fastr.java.class('" + Short.class.getName() + "'); t <- .fastr.interop.new(tc, .fastr.interop.toShort(1)); t", "1"); + assertEvalFastR("tc <- .fastr.java.class('" + String.class.getName() + "'); t <- .fastr.interop.new(tc, 'abc'); t", "'abc'"); + assertEvalFastR("tc <- .fastr.java.class('" + TestNullClass.class.getName() + "'); t <- .fastr.interop.new(tc, NULL); class(t)", "'" + RType.TruffleObject.getName() + "'"); + } + + @Test + public void testFields() throws IllegalArgumentException, IllegalAccessException { + TestClass t = new TestClass(); + Field[] fields = t.getClass().getDeclaredFields(); + for (Field f : fields) { + String name = f.getName(); + if (name.startsWith("field")) { + testForValue(name, f.get(t)); + } + } + } + + @Test + public void testMethods() throws IllegalAccessException, ClassNotFoundException, IllegalArgumentException, InvocationTargetException { + TestClass t = new TestClass(); + Method[] methods = t.getClass().getDeclaredMethods(); + for (Method m : methods) { + if (m.getParameterCount() == 0) { + String name = m.getName(); + if (name.startsWith("method")) { + testForValue(name + "()", m.invoke(t)); + } + } + } + } + + private void testForValue(String member, Object value) { + assertEvalFastR("tc <- .fastr.java.class('" + TEST_CLASS + "'); t <- .fastr.interop.new(tc); t$" + member, getRValue(value)); + } + + @Test + public void testAllTypes() { + getValueForAllTypesMethod("allTypesMethod"); + getValueForAllTypesMethod("allTypesStaticMethod"); + } + + @Test + public void testNonPrimitiveParameter() { + assertEvalFastR("tc <- .fastr.java.class('" + TEST_CLASS + "'); t <- .fastr.interop.new(tc); t$equals(t)", getRValue(true)); + } + + private void getValueForAllTypesMethod(String method) { + boolean bo = true; + byte bt = Byte.MAX_VALUE; + char c = 'a'; + short sh = Short.MAX_VALUE; + int i = Integer.MAX_VALUE; + long l = Long.MAX_VALUE; + double d = Double.MAX_VALUE; + float f = Float.MAX_VALUE; + String s = "testString"; + assertEvalFastR("tc <- .fastr.java.class('" + TEST_CLASS + "'); t <- .fastr.interop.new(tc); t$" + method + "(" + getRValue(bo, bt, c, sh, i, l, d, f, s) + ")", + getRValue("" + bo + bt + c + sh + i + l + d + f + s)); + } + + @Test + public void testNullParameter() { + assertEvalFastR(Ignored.Unimplemented, "tc <- .fastr.java.class('" + TEST_CLASS + "'); t <- .fastr.interop.new(tc); t$isNull('string')", "java.lang.String"); + assertEvalFastR(Ignored.Unimplemented, "tc <- .fastr.java.class('" + TEST_CLASS + "'); t <- .fastr.interop.new(tc); t$isNull(1)", "java.lang.Long"); + } + + @Test + public void testOverloaded() { + assertEvalFastR(Ignored.Unimplemented, "tc <- .fastr.java.class('" + TEST_CLASS + "'); t <- .fastr.interop.new(tc); t$isOverloaded(TRUE)", "boolean"); + assertEvalFastR(Ignored.Unimplemented, "tc <- .fastr.java.class('" + TEST_CLASS + "'); t <- .fastr.interop.new(tc); t$isOverloaded('string')", String.class.getName()); + // TODO add remaining isOverloaded(...) calls once this is fixed + } + + private String getRValue(Object value) { + if (value == null) { + return "NULL"; + } + if (value instanceof Boolean) { + return value.toString().toUpperCase(); + } + if (value instanceof String) { + return "\"" + value.toString() + "\""; + } + if (value instanceof Character) { + return "\"" + ((Character) value).toString() + "\""; + } + if (value.getClass().isArray()) { + StringBuilder sb = new StringBuilder(); + int l = Array.getLength(value); + sb.append("cat('[1] "); + for (int i = 0; i < l; i++) { + sb.append(getRValue(Array.get(value, i))); + if (i < l - 1) { + sb.append(" "); + } + } + sb.append("\\nattr(,\"is.truffle.object\")\\n[1] TRUE\\n')"); + return sb.toString(); + } + + return value.toString(); + } + + private String getRValue(Object... values) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < values.length; i++) { + Object v = values[i]; + sb.append(getRValue(v)); + if (i < values.length - 1) { + sb.append(","); + } + } + return sb.toString(); + } + + public static class TestNullClass { + public TestNullClass(Object o) { + assert o == null; + } + } + + public static class TestClass { + + public static boolean fieldStaticBoolean = true; + public static byte fieldStaticByte = Byte.MAX_VALUE; + public static char fieldStaticChar = 'a'; + public static short fieldStaticShort = Short.MAX_VALUE; + public static int fieldStaticInteger = Integer.MAX_VALUE; + public static long fieldStaticLong = Long.MAX_VALUE; + public static double fieldStaticDouble = Double.MAX_VALUE; + public static float fieldStaticFloat = Float.MAX_VALUE; + + public static Boolean fieldStaticBooleanObject = fieldStaticBoolean; + public static Byte fieldStaticByteObject = fieldStaticByte; + public static Character fieldStaticCharObject = fieldStaticChar; + public static Short fieldStaticShortObject = fieldStaticShort; + public static Integer fieldStaticIntegerObject = fieldStaticInteger; + public static Long fieldStaticLongObject = fieldStaticLong; + public static Double fieldStaticDoubleObject = fieldStaticDouble; + public static Float fieldStaticFloatObject = fieldStaticFloat; + public static String fieldStaticStringObject = "a string"; + + public boolean fieldBoolean = fieldStaticBoolean; + public byte fieldByte = fieldStaticByte; + public char fieldChar = fieldStaticChar; + public short fieldShort = fieldStaticShort; + public int fieldInteger = fieldStaticInteger; + public long fieldLong = fieldStaticLong; + public double fieldDouble = fieldStaticDouble; + public float fieldFloat = fieldStaticFloat; + + public Boolean fieldBooleanObject = fieldBoolean; + public Byte fieldByteObject = fieldByte; + public Character fieldCharObject = fieldChar; + public Short fieldShortObject = fieldShort; + public Integer fieldIntegerObject = fieldInteger; + public Long fieldLongObject = fieldLong; + public Double fieldDoubleObject = fieldDouble; + public Float fieldFloatObject = fieldFloat; + public String fieldStringObject = fieldStaticStringObject; + + public static Double fieldStaticNaNObject = Double.NaN; + public static double fieldStaticNaN = Double.NaN; + + public static int[] fieldStaticIntArray = new int[]{1, 2, 3}; + public static String[] fieldStaticStringArray = new String[]{"a", "b", "c"}; + + public int[] fieldIntArray = fieldStaticIntArray; + public String[] fieldStringArray = fieldStaticStringArray; + + public static Object fieldStaticNullObject = null; + public Object fieldNullObject = null; + + public TestClass() { + this(true, Byte.MAX_VALUE, 'a', Double.MAX_VALUE, Float.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, Short.MAX_VALUE, "a string"); + } + + public TestClass(boolean bo, byte bt, char c, double d, float f, int i, long l, short sh, String st) { + fieldStaticBoolean = bo; + fieldStaticByte = bt; + fieldStaticChar = c; + fieldStaticDouble = d; + fieldStaticFloat = f; + fieldStaticInteger = i; + fieldStaticLong = l; + fieldStaticShort = sh; + fieldStaticStringObject = st; + + // fieldStaticIntArray = ia; + // fieldStaticStringArray = sta; + + fieldStaticBooleanObject = fieldStaticBoolean; + fieldStaticByteObject = fieldStaticByte; + fieldStaticCharObject = fieldStaticChar; + fieldStaticShortObject = fieldStaticShort; + fieldStaticIntegerObject = fieldStaticInteger; + fieldStaticLongObject = fieldStaticLong; + fieldStaticDoubleObject = fieldStaticDouble; + fieldStaticFloatObject = fieldStaticFloat; + + this.fieldBoolean = fieldStaticBoolean; + this.fieldByte = fieldStaticByte; + this.fieldChar = fieldStaticChar; + this.fieldShort = fieldStaticShort; + this.fieldInteger = fieldStaticInteger; + this.fieldLong = fieldStaticLong; + this.fieldDouble = fieldStaticDouble; + this.fieldFloat = fieldStaticFloat; + + this.fieldBooleanObject = fieldBoolean; + this.fieldByteObject = fieldByte; + this.fieldCharObject = fieldChar; + this.fieldShortObject = fieldShort; + this.fieldIntegerObject = fieldInteger; + this.fieldLongObject = fieldLong; + this.fieldDoubleObject = fieldDouble; + this.fieldFloatObject = fieldFloat; + this.fieldStringObject = fieldStaticStringObject; + + this.fieldIntArray = fieldStaticIntArray; + this.fieldStringArray = fieldStaticStringArray; + } + + public static boolean methodStaticBoolean() { + return fieldStaticBoolean; + } + + public static byte methodStaticByte() { + return fieldStaticByte; + } + + public static char methodStaticChar() { + return fieldStaticChar; + } + + public static short methodStaticShort() { + return fieldStaticShort; + } + + public static int methodStaticInteger() { + return fieldStaticInteger; + } + + public static long methodStaticLong() { + return fieldStaticLong; + } + + public static double methodStaticDouble() { + return fieldStaticDouble; + } + + public static float methodStaticFloat() { + return fieldStaticFloat; + } + + public static String methodStaticStringObject() { + return fieldStaticStringObject; + } + + public static String[] methodStaticStringArray() { + return fieldStaticStringArray; + } + + public static int[] methodStaticIntArray() { + return fieldStaticIntArray; + } + + public boolean methodBoolean() { + return fieldBoolean; + } + + public byte methodByte() { + return fieldByte; + } + + public char methodChar() { + return fieldChar; + } + + public short methodShort() { + return fieldShort; + } + + public int methodInteger() { + return fieldInteger; + } + + public long methodLong() { + return fieldLong; + } + + public double methodDouble() { + return fieldDouble; + } + + public float methodFloat() { + return fieldFloat; + } + + public String methodStringObject() { + return fieldStringObject; + } + + public String[] methodStringArray() { + return fieldStringArray; + } + + public int[] methodIntArray() { + return fieldIntArray; + } + + public static Boolean methodStaticBooleanObject() { + return fieldStaticBooleanObject; + } + + public static Byte methodStaticByteObject() { + return fieldStaticByteObject; + } + + public static Character methodStaticCharObject() { + return fieldStaticCharObject; + } + + public static Short methodStaticShortObject() { + return fieldStaticShortObject; + } + + public static Integer methodStaticIntegerObject() { + return fieldStaticIntegerObject; + } + + public static Long methodStaticLongObject() { + return fieldStaticLongObject; + } + + public static Double methodStaticDoubleObject() { + return fieldStaticDoubleObject; + } + + public static Float methodStaticFloatObject() { + return fieldStaticFloatObject; + } + + public Boolean methodBooleanObject() { + return fieldBoolean; + } + + public Byte methodByteObject() { + return fieldByteObject; + } + + public Character methodCharObject() { + return fieldCharObject; + } + + public Short methodShortObject() { + return fieldShortObject; + } + + public Integer methodIntegerObject() { + return fieldIntegerObject; + } + + public Long methodLongObject() { + return fieldLongObject; + } + + public Double methodDoubleObject() { + return fieldDoubleObject; + } + + public Float methodFloatObject() { + return fieldFloatObject; + } + + public static Object methodStaticReturnsNull() { + return null; + } + + public Object methodReturnsNull() { + return null; + } + + public String allTypesMethod(boolean bo, byte bt, char ch, short sh, int in, long lo, double db, float fl, String st) { + return "" + bo + bt + ch + sh + in + lo + db + fl + st; + } + + public static Object allTypesStaticMethod(boolean bo, byte bt, char ch, short sh, int in, long lo, double db, float fl, String st) { + return "" + bo + bt + ch + sh + in + lo + db + fl + st; + } + + public String isNull(String s) { + return s == null ? String.class.getName() : null; + } + + public String isNull(Long l) { + return l == null ? Long.class.getName() : null; + } + + 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(); + } + } +}